Comparing Object Comparison with Hash List
I am looking for troubleshooting help comparing .key values to objects.
Basically what happens here is I connect to two VMware vCenters and load a list of roles and put those roles into two hash tables and then compare them.
The problem comes down to the Process-Roles function, where the comparison logic is incorrect. It lists all roles in both lists. I think (-necontainer) is not working correctly. I have been debugging powerGUI and both hashtables and mstr_roles / slave_roles are filled in correctly.
Role lists must be object lists as they are populated with Get-VIRole. The hash table must be object-key, null-valued lists. Can the two be compared? I am trying to check if a $ role object exists in a list of roles in a .key hash table.
$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"
}
source to share
The easiest way to do this is to find the complement to one of the two sets of keys that each hash table has, using -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"
}
}
I must add that your way of working with variables in different scopes is not optimal.
- Determine the parameters required for the function to do its job
- Returns output from your functions where it makes sense (any function
Get-*
should be a minimum) - Depends on global and Script scopes as little as possible, preferably not all
Instead, I would do something like this:
Add a parameter Credential
to the function Get-Roles
and return the results, rather than modifying the variable in the parent scope (here using the Role Category Hashtable):
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
}
Define the parameters for the function Process-Roles
that match the hash table you expect to generate from, Get-Roles
and do the same comparison of role names as above, only this time we grab them directly from the Role objects:
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"
}
Update your Script executable with new parameters:
$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
The next step would be to add pipeline support to the function Process-Roles
, convert operators Write-Host
to, Write-Verbose
and add error handling, but I'll leave that as an exercise for the OP :-)
source to share