We all know that the Standard switch is normally used for the management network of the hosts, and this switch has configurable uplinks (for example Active & Standby uplinks).
Today I was analysing a host failure on the weekend where one of the uplinks went down but a few hosts went into network isolation- isolating themselves from the vCenter. I checked the Standard switch uplinks and they are both Active.
I then checked the Management PortGroup, as it too can have configured uplinks, and I found one of the uplinks configured as StandBy, and thus the reason why those hosts failed.
I now want to run a PowerShell script to check all hosts in the cluster and I came up with this, with help from an existing script I found:
&{foreach($esx in Get-VMHost){
$vNicTab = @{}
$esx.ExtensionData.Config.Network.Vnic | %{
$vNicTab.Add($_.Portgroup,$_)
}
foreach($vsw in (Get-VirtualSwitch -VMHost $esx -Standard)){
foreach($pg in (Get-VirtualPortGroup -VirtualSwitch $vsw)){
Select -InputObject $pg -Property @{N="ESX";E={$esx.name}},
@{N="vSwitch";E={$vsw.Name}},
@{N="Active NIC";E={[string]::Join(',',$vsw.ExtensionData.Spec.Policy.NicTeaming.NicOrder.ActiveNic)}},
@{N="Standby NIC";E={[string]::Join(',',$vsw.ExtensionData.Spec.Policy.NicTeaming.NicOrder.StandbyNic)}},
@{N="Portgroup";E={$pg.Name}},
@{N="VLAN";E={$pg.VLanId}},
@{N="Device";E={if($vNicTab.ContainsKey($pg.Name)){$vNicTab[$pg.Name].Device}}},
@{N="IP";E={if($vNicTab.ContainsKey($pg.Name)){$vNicTab[$pg.Name].Spec.Ip.IpAddress}}},
@{N="PortGroup Active NIC";E={Get-VirtualPortGroup -Name $PG.Name | Get-NICTeamingPolicy | Select ActiveNic}},
@{N="PortGroup StandBy NIC";E={Get-VirtualPortGroup -Name $PG.Name | Get-NICTeamingPolicy | Select StandByNic}}
}
}
}}
My problem is with the returned values for "PortGroup Active NIC" & "PortGroup StandBy NIC" which appear like this:
PortGroup Active NIC : {@{ActiveNic=System.String[]}, @{ActiveNic=System.String[]}, @{ActiveNic=System.String[]}, @{ActiveNic=System.String[]}...}
PortGroup StandBy NIC : {@{StandbyNic=}, @{StandbyNic=}, @{StandbyNic=}, @{StandbyNic=}...}
If I run the command from the commandline, I get this:
$Z = Get-VirtualPortGroup -Name $PG.Name | Get-NICTeamingPolicy | Select ActiveNic
$Z
ActiveNic
---------
{vmnic0, vmnic3}
$z.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
My goal is to set the property "PortGroup Active NIC" to "vmnic0, vmnic3".
From the commandline, this seems to work:
$Z.ActiveNic -join ", "
vmnic0, vmnic3
I'm not sure how to do this in the original code tho.
Can you try with
@{N = "PortGroup Active NIC"; E = { (Get-VirtualPortGroup -Name $PG.Name -VMHost $esx -VirtualSwitch $sw | Get-NicTeamingPolicy).ActiveNic.Where{ $_ } -join ',' } },
@{N = "PortGroup StandBy NIC"; E = { (Get-VirtualPortGroup -Name $PG.Name -VMHost $esx -VirtualSwitch $sw | Get-NicTeamingPolicy).StandByNic.Where{ $_} -join ',' } }
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Try with
@{N = "PortGroup Active NIC"; E = { (Get-VirtualPortGroup -Name $PG.Name | Get-NicTeamingPolicy).ActiveNic.Where{$_} -join ',' } },
@{N = "PortGroup StandBy NIC"; E = { (Get-VirtualPortGroup -Name $PG.Name | Get-NicTeamingPolicy).StandByNic.Where{ $_} -join ',' } }
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
For the Management port group of my test host, I purposely put vmnic0 as active and vmnic4 as unused and got the following results:
ESX : MyHostNameAtMyDomain.Com
vSwitch : vSwitch0
Active NIC : vmnic0,vmnic4
Standby NIC :
Portgroup : Management Network
VLAN : 1000
Device : vmk0
IP : 1172.0.0.102
PortGroup Active NIC : vmnic0, vmnic1, vmnic3, vmnic3, vmnic1, vmnic3, vmnic1, vmnic1, vmnic3, vmnic3, vmnic1, vmnic1, vmnic3, vmnic1, vmnic3, vmnic0, vmnic1, vmnic0, vmnic1, vmnic0, vmnic3, vmnic0,
vmnic3, vmnic0, vmnic3, vmnic0, vmnic3, vmnic1, vmnic3, vmnic3, vmnic1, vmnic0, vmnic3, vmnic1, vmnic3, vmnic3, vmnic1, vmnic3, vmnic1, vmnic3, vmnic2, vmnic3, vmnic1, vmnic2,
vmnic3, vmnic0, vmnic3, vmnic1, vmnic3, vmnic3, vmnic2, vmnic1, vmnic3, vmnic3, vmnic2, vmnic0, vmnic3, vmnic0, vmnic3, vmnic0, vmnic3, vmnic2, vmnic3, vmnic2, vmnic3, vmnic2,
vmnic3, vmnic2, vmnic3, vmnic3, vmnic2, vmnic0, vmnic1, vmnic0, vmnic1, vmnic0, vmnic2, vmnic4, vmnic5, vmnic2, vmnic3, vmnic2, vmnic3, vmnic0, vmnic3, vmnic0, vmnic3, vmnic0,
vmnic3, vmnic1, vmnic3, vmnic3, vmnic1, vmnic2, vmnic3, vmnic1, vmnic2, vmnic3, vmnic3, vmnic1, vmnic3, vmnic1, vmnic3, vmnic1, vmnic2, vmnic3, vmnic3, vmnic1, vmnic2, vmnic3,
vmnic2, vmnic3, vmnic0, vmnic3, vmnic1, vmnic3, vmnic3, vmnic2, vmnic0, vmnic3, vmnic0, vmnic3, vmnic0, vmnic7, vmnic0, vmnic7, vmnic1, vmnic3, vmnic1, vmnic3, vmnic1, vmnic3,
vmnic2, vmnic3, vmnic0, vmnic0, vmnic0, vmnic3, vmnic0, vmnic0, vmnic3, vmnic0, vmnic4, vmnic0, vmnic4, vmnic2, vmnic3, vmnic2, vmnic3
PortGroup StandBy NIC : vmnic3, vmnic3, vmnic3
Which does not seem right.
I manually ran each line as such:
$esx = Get-VMHost -Name 'MyHostAtMyDomain.Com'
$vsw = (Get-VirtualSwitch -VMHost $esx -Standard)
$vsw
Name NumPorts Mtu Notes
---- -------- --- -----
vSwitch0 11776 1500
$pg = (Get-VirtualPortGroup -VirtualSwitch $vsw)
$pg
Name Key VLanId PortBinding NumPorts
---- --- ------ ----------- --------
Management Network key-vim.host.PortGroup-Mana... 1000
VM Network key-vim.host.PortGroup-VM N... 0
Get-VirtualPortGroup -Name $PG[0].Name | Get-NICTeamingPolicy
VirtualPortGroup ActiveNic StandbyNic UnusedNic FailbackEnabled NotifySwitches
---------------- --------- ---------- --------- --------------- --------------
Management Network {vmnic0} {vmnic3} True True
Management Network {vmnic1, vmn... True True
Management Network {vmnic3, vmn... True True
Management Network {vmnic3, vmn... True True
Management Network {vmnic1, vmn... True True
Management Network {vmnic3, vmn... True True
Management Network {vmnic1, vmn... True True
Management Network {vmnic1, vmn... True True
Management Network {vmnic0, vmn... True True
Management Network {vmnic0, vmn... True True
Looks like there may be something wrong with $PG?
Can you try with
@{N = "PortGroup Active NIC"; E = { (Get-VirtualPortGroup -Name $PG.Name -VMHost $esx -VirtualSwitch $sw | Get-NicTeamingPolicy).ActiveNic.Where{ $_ } -join ',' } },
@{N = "PortGroup StandBy NIC"; E = { (Get-VirtualPortGroup -Name $PG.Name -VMHost $esx -VirtualSwitch $sw | Get-NicTeamingPolicy).StandByNic.Where{ $_} -join ',' } }
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
That worked well, thanks. Can you explain how this line works?
.ActiveNic.Where{ $_ }
To me it looks like, if the port group $PG exists, then......do this.
Amazing solution btw.
One other question: I ran the modified code for all distributed switches and it's been running for 24 hours now- we only have about 3 distributed switches in our environment. I presume that this line is taking a while to run, is there any way to modify the code so that the line runs once and the properties ActiveNic, StandByNic & UnusedNic can be added to the collection?
Get-VirtualPortGroup -Name $PG.Name -VMHost $esx -VirtualSwitch $vsw | Get-NicTeamingPolicy
I also modified the script so that it should be able to report on only either Standard or Distributed switches, here's the modifications:
Param (
[Switch]$Standard,
[Switch]$Distributed
)
Write-Host "Script Starting" -ForegroundColor Green
# &{foreach($esx in Get-VMHost -Name 'cmspp2ensxthp10.iaas01.bsg.interactive.com.au'){
&{foreach($esx in Get-VMHost){
$vNicTab = @{}
$esx.ExtensionData.Config.Network.Vnic | %{
if (-not $vNicTab.ContainsKey($_.Portgroup))
{
$vNicTab.Add($_.Portgroup,$_)
}
}
if ($Standard.IsPresent -or $Distributed.IsPresent)
{
if ($Distributed.IsPresent)
{
$oSwitchObject = Get-VirtualSwitch -VMHost $esx -Distributed
$Standard = $False
Write-Host "Distributed switches only"
}
if ($Standard.IsPresent)
{
$oSwitchObject = Get-VirtualSwitch -VMHost $esx -Standard
Write-Host "Standard switches only"
}
}
Else
{
$oSwitchObject = Get-VirtualSwitch -VMHost $esx -Standard
Write-Host "Standard switches only"
}
Write-Host "Working on host [$ESX.Name]"
foreach($vsw in ($oSwitchObject)){
Write-Host "-- Virtual Switch [$VSW]" -ForegroundColor Blue
foreach($pg in (Get-VirtualPortGroup -VirtualSwitch $vsw)){
Write-Host "---- Port Group [$PG]" -ForegroundColor Cyan
Select -InputObject $pg -Property @{N="ESX";E={$esx.name}},
@{N="vSwitch";E={$vsw.Name}},
@{N="vSwitch Active NIC";E={[string]::Join(',',$vsw.ExtensionData.Spec.Policy.NicTeaming.NicOrder.ActiveNic)}},
@{N="vSwitch Standby NIC";E={[string]::Join(',',$vsw.ExtensionData.Spec.Policy.NicTeaming.NicOrder.StandbyNic)}},
@{N="vSwitch Unused NIC";E={[string]::Join(',',$vsw.ExtensionData.Spec.Policy.NicTeaming.NicOrder.UnusedNic)}},
@{N="Portgroup";E={$pg.Name}},
@{N="PortGroup VLAN";E={$pg.VLanId}},
@{N="Device";E={if($vNicTab.ContainsKey($pg.Name)){$vNicTab[$pg.Name].Device}}},
@{N="IP";E={if($vNicTab.ContainsKey($pg.Name)){$vNicTab[$pg.Name].Spec.Ip.IpAddress}}},
@{N="PortGroup Active NIC"; E = { (Get-VirtualPortGroup -Name $PG.Name -VMHost $esx -VirtualSwitch $vsw | Get-NicTeamingPolicy).ActiveNic.Where{ $_ } -join ',' } },
@{N="PortGroup StandBy NIC"; E = { (Get-VirtualPortGroup -Name $PG.Name -VMHost $esx -VirtualSwitch $vsw | Get-NicTeamingPolicy).StandByNic.Where{ $_} -join ',' } },
@{N="PortGroup Unused NIC"; E = { (Get-VirtualPortGroup -Name $PG.Name -VMHost $esx -VirtualSwitch $vsw | Get-NicTeamingPolicy).UnusedNic.Where{ $_} -join ',' } }
}
}
}} | Export-Csv ManagementPortGroupNICReport.csv -NoTypeInformation -UseCulture
Write-Host "Script Stopping" -ForegroundColor Green
Thanks.
That is an alternative to the Where-Object cmdlet.
It's faster, that's why I prefer to use it this way.
It tests if there is a value in the elements of the ActiveNic and StandbyNic arrays.
Without that test you would end up with a number of commas without values between them.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference