powershell - 对象与哈希表键比较

标签 powershell vmware powercli

我正在寻找一些帮助来解决比较 .key 值与对象的问题。

基本上这里发生的事情是我连接到两个 VMware vCenter 并下载角色列表并将这些角色放入两个哈希表中,然后比较它们。

问题归结为 Process-Roles 函数,其中比较逻辑在某处存在缺陷。它输出两个列表中的所有角色。我认为 (-not .containskey) 不能正常工作。我已经在 powerGUI 中进行了调试,哈希表和 mstr_roles/slave_roles 都已正确填充。

角色列表应该是对象列表,因为它们是用 Get-VIRole 填充的。 哈希表应该是键中对象,值空列表。可以比较这两个吗?我正在尝试检查角色列表中的 $role 对象是否存在于哈希表的 .key 值列表中。

$creds = Get-Credential
$mst = Read-Host "`n Master Server: "
$slv = Read-Host "`n Slave Server: "
$hsh_mstr_roles = @{}
$hsh_slave_roles = @{}
$mstr_roles = ""
$slave_roles = ""

Get-Roles -MasterServer $mst -SlaveServer $slv

Process-Roles 

.

function Get-Roles() {
Param(
 [Parameter(Mandatory=$True,Position=0)]
 [string]$MasterServer,

 [Parameter(Mandatory=$True,Position=1)]
 [string]$SlaveServer
 )

#Get Master Roles
Connect-VIServer $MasterServer -Credential $creds

$mstr_roles = Get-VIrole

foreach ($role in $mstr_roles) {
    $hsh_mstr_roles.add($role, $null)
}

Disconnect-VIServer $MasterServer -Confirm:$false

#Get Slave Roles
Connect-VIServer $SlaveServer -Credential $creds

$slave_roles = Get-VIrole

foreach ($role in $slave_roles) {
    $hsh_slave_roles.add($role, $null)
}

Disconnect-VIServer $SlaveServer -Confirm:$false

Write-Host "`n + Retrieved Roles Successfully"
}    

.

function Process-Roles () { 
#Get Roles on Master NOT ON SLAVE

Write-Host "`n"

foreach ($role in $mstr_roles){
    if(-not $hsh_slave_roles.containsKey($role)){
    Write-Host $role "doesn't exist on slave"
    }
}

#Get Roles on Slave NOT ON MASTER
foreach ($role in $slave_roles){
    if(-not $hsh_mstr_roles.containsKey($role)){
    Write-Host $role "doesn't exist on master"
    }
}

Write-Host "`n + Processed Roles Successfully"
}

最佳答案

最简单的方法是使用 -notcontains 找到每个哈希表具有的两组键之一的补码:

function Process-Roles {
    param(
        [hashtable]$MasterRoles,
        [hashtable]$SlaveRoles
    )

    # Complement to slave roles (those ONLY in $MasterRoles)
    $MasterRoles.Keys |Where-Object { $SlaveRoles -notcontains $_ }|ForEach-Object {
        Write-Host "$_ not in Slave Roles"
    } 

    # and the other way around (those ONLY in $SlaveRoles)
    $SlaveRoles.Keys |Where-Object { $MasterRoles -notcontains $_ }|ForEach-Object {
        Write-Host "$_ not in Master Roles"
    } 

}

我必须补充一点,您在不同范围内处理变量的方式不是最优的。

  1. 定义函数“完成其工作”所需的参数
  2. 从您的函数返回有意义的输出(任何 Get-* 函数至少应该)
  3. 尽可能少地依赖全局和脚本范围,最好完全不依赖

我会选择这样的东西:

Credential 参数添加到 Get-Roles 函数并返回结果,而不是修改父作用域中的变量(此处使用角色类别的哈希表) :

function Get-Roles {
    Param(
        [Parameter(Mandatory=$True,Position=0)]
        [string]$MasterServer,

        [Parameter(Mandatory=$True,Position=1)]
        [string]$SlaveServer,

        [Parameter(Mandatory=$True,Position=2)]
        [pscredential]$Credential
    )

    $DiscoveredRoles = @{}

    # Get Master Roles
    Connect-VIServer $MasterServer -Credential $Credential
    $DiscoveredRoles["MasterRoles"] = Get-VIRole
    Disconnect-VIServer $MasterServer -Confirm:$false

    #Get Slave Roles
    Connect-VIServer $SlaveServer -Credential $Credential
    $DiscoveredRoles["SlaveRoles"] = Get-VIrole
    Disconnect-VIServer $SlaveServer -Confirm:$false

    Write-Verbose "`n + Retrieved Roles Successfully"

    return $DiscoveredRoles

}    

Process-Roles 函数定义参数,匹配您希望从 Get-Roles 生成的哈希表,并像上面一样对角色名称进行相同的比较,只是这一次我们直接从 Role 对象中获取它们:

function Process-Roles { 
    param(
        [Parameter(Mandatory=$true)]
        [ValidateScript({ $_.ContainsKey("MasterRoles") -and $_.ContainsKey("SlaveRoles") })]
        [hashtable]$RoleTable
    )

    $MasterRoleNames = $RoleTable["MasterRoles"] |Select-Object -ExpandProperty Name

    $SlaveRoleNames = $RoleTable["SlaveRoles"] |Select-Object -ExpandProperty Name

    $MasterRoleNames |Where-Object { $SlaveRoleNames -notcontains $_ } |ForEach-Object {
        Write-Host "$_ doesn't exist on slave"    
    }

    $SlaveRoleNames |Where-Object { $MasterRoleNames -notcontains $_ } |ForEach-Object {
        Write-Host "$_ doesn't exist on Master"    
    }

    Write-Host "`n + Processed Roles Successfully"
}

使用新参数更新您的执行脚本:

$creds = Get-Credential
$MasterServer = Read-Host "`n Master Server: "
$SlaveServer  = Read-Host "`n Slave Server: "

$RoleTable = Get-Roles -MasterServer $MasterServer -SlaveServer $SlaveServer -Credential $creds

Process-Roles -RoleTable $RoleTable

下一步是为 Process-Roles 函数添加管道支持,将 Write-Host 语句转换为 Write-Verbose 并添加错误处理,但我会将其作为练习留给 OP :-)

关于powershell - 对象与哈希表键比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31810803/

相关文章:

sql-server - 等待 AWS RDS native sql 备份完成

.net - 来自 Windows 批处理脚本的文件/文件夹选择器对话框

c# - 无需 TFS 或 VSTS 自动部署 Service Fabric 项目

vmware - 使用 VMWare Player 5,如何通过外部机器访问在 VM 中运行的 Web 服务器?

powershell - 在 PowerCLI 中比较 2 个对象

powershell - 那么Powershell PSC1 文件有什么特别之处呢?

匹配 PowerShell 代码中的 "here strings"的正则表达式

php - 如何通过 PHP 使用 VMware VSphere API 创建新虚拟机

usb - 如何使用 VMware vmrun 管理 USB 设备?

powershell - powercli Get-VM 不匹配标签