对象到哈希表键比较

时间:2015-08-04 13:35:25

标签: powershell vmware powercli

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

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

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

角色列表应该是对象列表,因为它们是用Get-VIRole填充的。 哈希表应该是object-in-key,value null列表。有可能比较这两个吗?我试图检查角色列表中的$ 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"
}

2 个答案:

答案 0 :(得分:3)

最简单的方法是使用-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. 尽可能少地依赖全局和脚本范围,最好不要
  4. 我会选择这样的东西:

    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生成的哈希表相匹配,并对上述角色名称进行相同的比较,但这次我们直接从角色中获取它们对象:

    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: - )

答案 1 :(得分:1)

尝试:

if(!$hsh_slave_roles.containsKey($role))