VMware Cloud Community
PetarHavezov
Contributor
Contributor

PowerCLI function to get Hosts NICs CDP/LLDP/vSwitch Info end-to-end

I’m trying to make multiple vSphere informational function to simplify my work (maybe if they are mature enough I will combine them in a PS module in the future).

One of this function is to get all information of ESXi host physical NIC, including CDP and LLDP information and get full visibility picture end to end from vmnic to physical switch port.

I’m satisfied with the speed of my script. But not satisfied in one of core component - Host vmnic relationship with the vSwitches (VDS and Standard) .

I found some approaches for this task in other scripts like

My Approach for Host NICs assignment to vSwitch/dvSwitch is

$vSwitchesNics=@()

$vSwitches = $EsxHost |Get-VirtualSwitch

  foreach ($vSwitch in $vSwitches) { 

    if ($vSwitch.nic) {              #VSS Filter

              foreach ($Nic in $vSwitch.nic) {  $vSwitchesNics+= $vSwitch |Select @{N="Name";E={$vSwitch.name}}, @{N="Nic";E={$Nic}}  }

                            }

    elseif ($vSwitch.DataCenter) {    #VDS Filter

              $vSwitchesNics+= $EsxHost | Get-VMHostNetworkAdapter -Physical -DistributedSwitch $vSwitch | Select @{N="Name";E={$vSwitch.name}}, @{N="Nic";E={$_.DeviceName}}

                                  }

       }

$vSwitchesNics

Using Get-VirtualSwitch with VDS is not very good, because "This behavior is obsolete and may change in the future. To retrieve distributed switches, use

Get-VDSwitch cmdlet in the VDS component. To retrieve standard switches, use -Standard".

Without vSwitch Info the function is:

function Info-EsxNic {
   param(
   [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
   [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl[]]$EsxHost
    )

  process {
  $Esxcli = Get-Esxcli -VMHost $EsxHost.name -V2
  $EsxcliInfo=$esxcli.network.nic.list.invoke()
  $NetworkView = Get-View ((Get-View $EsxHost).Configmanager.Networksystem)
 
  $EsxHost | Get-VMHostNetworkAdapter -Physical | Select @{N="EsxName";E={$_.VMHost}},
  @{N="PnicName";E={$_.DeviceName}},
  @{N="PnicMacAddress";E={$_.Mac}},
  @{N="Link";E={ ($EsxcliInfo | Where Name -eq $_.DeviceName).LinkStatus }},
  @{N="SpeedMb";E={$_.ExtensionData.LinkSpeed.SpeedMb}},
  @{N="DProtocol";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {"CDP"} elseif ( ($NetworkView.QueryNetworkHint($_)).LldpInfo) {"LLDP"} else {"NA"}  }},
  @{N="SwitchName";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort.DevId}
       elseif (($NetworkView.QueryNetworkHint($_)).LldpInfo) {(($NetworkView.QueryNetworkHint($_)).LldpInfo.Parameter | where key -eq "System Name").Value}  }},
  @{N="SwitchPort";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort.PortId}
       elseif ( ($NetworkView.QueryNetworkHint($_)).LldpInfo) {($NetworkView.QueryNetworkHint($_)).LldpInfo.PortId}  }},
  @{N="SwitchAddress";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort.MgmtAddr}
       elseif (($NetworkView.QueryNetworkHint($_)).LldpInfo) {(($NetworkView.QueryNetworkHint($_)).LldpInfo.Parameter | where key -eq "Management Address").Value} }},
  @{N="SwitchId";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort.HardwarePlatform}
       elseif ( ($NetworkView.QueryNetworkHint($_)).LldpInfo) {($NetworkView.QueryNetworkHint($_)).LldpInfo.ChassisId}  }},
  @{N="PnicModel";E={ ($EsxcliInfo | Where Name -eq $_.DeviceName).Description }},
  @{N="PnicDriver";E={$_.ExtensionData.Driver}},
  @{N="PciSlot";E={$_.ExtensionData.Pci}}
}
}

With vSwitch Info the function is:

function Info-EsxNicAll {
   param(
   [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
   [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl[]]$EsxHost
    )

  process {
  $Esxcli = Get-Esxcli -vmhost $EsxHost.name -V2
  $EsxcliInfo=$esxcli.network.nic.list.invoke()
  $NetworkView = Get-View ((Get-View $EsxHost).Configmanager.Networksystem)
 
  $vSwitchesNics=@()
  $vSwitches = $EsxHost |Get-VirtualSwitch
  foreach ($vSwitch in $vSwitches) { 
    if ($vSwitch.nic) {      #VSS Filter
  foreach ($Nic in $vSwitch.nic) {  $vSwitchesNics+= $vSwitch |Select @{N="Name";E={$vSwitch.name}}, @{N="Nic";E={$Nic}}  }
                 }
    elseif ($vSwitch.DataCenter) {    #VDS Filter
  $vSwitchesNics+= $EsxHost | Get-VMHostNetworkAdapter -Physical -DistributedSwitch $vSwitch | Select @{N="Name";E={$vSwitch.name}}, @{N="Nic";E={$_.DeviceName}}
        }
}
 
  $EsxHost | Get-VMHostNetworkAdapter -Physical | Select @{N="EsxName";E={$_.VMHost}},
  @{N="PnicName";E={$_.DeviceName}},
  @{N="PnicMacAddress";E={$_.Mac}},
  @{N="Link";E={ ($EsxcliInfo | Where Name -eq $_.DeviceName).LinkStatus }},
  @{N="SpeedMb";E={$_.ExtensionData.LinkSpeed.SpeedMb}},
  @{N="vSwitch";E={ ($vSwitchesNics | Where Nic -eq $_.DeviceName).Name } },
  @{N="DProtocol";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {"CDP"} elseif ( ($NetworkView.QueryNetworkHint($_)).LldpInfo) {"LLDP"} else {"NA"}  }},
  @{N="SwitchName";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort.DevId}
       elseif (($NetworkView.QueryNetworkHint($_)).LldpInfo) {(($NetworkView.QueryNetworkHint($_)).LldpInfo.Parameter | where key -eq "System Name").Value}  }},
  @{N="SwitchPort";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort.PortId}
       elseif ( ($NetworkView.QueryNetworkHint($_)).LldpInfo) {($NetworkView.QueryNetworkHint($_)).LldpInfo.PortId}  }},
  @{N="SwitchAddress";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort.MgmtAddr}
       elseif (($NetworkView.QueryNetworkHint($_)).LldpInfo) {(($NetworkView.QueryNetworkHint($_)).LldpInfo.Parameter | where key -eq "Management Address").Value} }},
  @{N="SwitchId";E={if (($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort) {($NetworkView.QueryNetworkHint($_)).ConnectedSwitchPort.HardwarePlatform}
       elseif ( ($NetworkView.QueryNetworkHint($_)).LldpInfo) {($NetworkView.QueryNetworkHint($_)).LldpInfo.ChassisId}  }},
  @{N="PnicModel";E={ ($EsxcliInfo | Where Name -eq $_.DeviceName).Description }},
  @{N="PnicDriver";E={$_.ExtensionData.Driver}},
  @{N="PciSlot";E={$_.ExtensionData.Pci}}
}
}

The Second function run 2 time slower in some situation in my environment, than the first one:

Usage

Get-VMHost | Info-EsxNic

Get-VMHost | Info-EsxNicAll

I will appreciate any help to improve my PowerCLI script in vSwitch-VMnic part, and in other parts of course. All CDP/LLDP code is not very readable but is fast, some simplification is also welcome.

0 Kudos
4 Replies
LucD
Leadership
Leadership

I'm not really sure what your question actually is.

There are a couple of methods to collect information about switches in a vSphere environment.

Not every method provides all available information.

The methods:

  • Cmdlets like Get-VirtualSwitch and Get-VDSwitch
    • These return a subset of information, selected by the PowerCLI Team
  • With 'Get-View'
    • With this cmdlet you have access to the actual, public vSphere objects, meaning all properties and methods. Some properties and methods are not exposed by the PowerCLI cmdlets
  • With 'esxcli'
    • The Get-EsxCli cmdlet gives a user access to the ESXi native esxcli command.

You can order these methods on execution speed and returned information.

For speed:

  1. Get-View  & Get-EsxCli
  2. Get-VirtualSwitch/Get-VdSwitch

For information:

  1. Get-View
  2. Get-EsxCli
  3. Get-VirtualSwitch/Get-VDSwitch

When you are developing a complex function, I personally advise to first provide a layout of what you want.
List all properties you want to be returned, then write your function with that in mind.
Even better is to first write the (Pester) tests, where you check that everything you want is actually returned in all circumstances.

After you have this step completed, start looking at execution speed.

With Get-View there are a number of optimisation possibilities.

For example, using the Property parameter can seriously improve execution speed.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
PetarHavezov
Contributor
Contributor

LucD thanks for your professional response. I appreciate your help and guidance.

The goal of this function is to provide end to end PNIC information – combining three components in one view

  1. ESX Host NIC Info (NIC Name, Mac Address, NIC Model, Speed, Link Status, NIC Driver, PCI Slot, MTU)  
  2. Virtual Switch Name (Standard/VDS) connected to current PNIC
  3. Physical Switch Info (using CDP and LLDP – Switch Name, Switch Port, Switch IP Address, Switch Model/ID, Port Description)

For 1. I am using Get-VMHostNetworkAdapter cmdlet, except NIC Link Status, which I get form Get-EsxCli (Is there another method for this?)

For 2. I am using temporary array $vSwitchesNics to build vmnic to vSwitch assignment info using Get-VirtualSwitch cmdlet. Than I am using this info in main part of the script

Get-VMHostNetworkAdapter -Physical | Select …, @{N="vSwitch";E={ ($vSwitchesNics | Where Nic -eq $_.DeviceName).Name } },

(I have question here – Is there direct way to get from vmnic perspective information for assign vSwitch, not using temporary array to build this info like my approach. If not possible to get-direct info, I want some help to improve code of filling $vSwitchesNics array

For 3. I am using Get-View (the only way I know to get information from Discovery Protocol - CDP/LLDP)

I’m SysAdmin no developer so I haven’t their best practice/habit how to test code. So I will read more about Pester test (I’m not familiar with this).

I execute my script against more than 70 ESXi hosts with different network configuration and vSphere version – we have CISCO ACI Infrastructure which VMware VDS Switch and LLDP integration. Cisco UCS Infrastructure with Fabric Interconnect using CDP, Cisco Hyperflex (with many VMware Standard vSwitches), Old School Classic DC Network infrastructure – Core/Aggregation/ Access using CDP and Cisco vSwitch Nexus 1000V. So far so good, no found error in script. In fact with script output information I found some mismatches in physical switches configuration which I escalate to network team. Like many SysAdmins I have much operational problems, so script like this help me much. So I want to make it more mature and usable to other people.

 

0 Kudos
LucD
Leadership
Leadership

The easiest way is to start from the VirtualSwitch to go to pNIC.

Since you already retrieved the NetworkSystem, you can use that object to retrive the info.

Something like this

$esx = Get-VMHost -Name MyEsx

$netSys = Get-View -Id $esx.ExtensionData.ConfigManager.NetworkSystem

$netSys.NetworkInfo.Vswitch |

ForEach-Object -Process {

    $vss = $_

    $vss.Pnic |

    Select @{N='Switch';E={$vss.name}},

        @{N='Type';E={'VSS'}},

        @{N='pNIC';E={$_.Split('-')[-1]}}

}

$netSys.NetworkInfo.ProxySwitch |

ForEach-Object -Process {

    $vds = $_

    $vds.Pnic |

    Select @{N='Switch';E={$vds.DvsName}},

        @{N='Type';E={'VDS'}},

        @{N='pNIC';E={$_.Split('-')[-1]}}

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
likeahoss
Enthusiast
Enthusiast

There's a VMware KB with code to grab the specs you're looking for.

https://kb.vmware.com/s/article/1007069 

0 Kudos