Get ESXi Host CDP Info With PowerCLI

Get ESXi Host CDP Info With PowerCLI

Introduction

I recently had to provide our networking team with a list of ESXi hosts and which switchports each of their physical NICs were connected to. Like many other environments, we are primarily a Cisco house and therefore I was able to get this data by querying the Cisco Discovery Protocol (CDP) information via PowerCLI. Here is how I went about it.

The Process

I will initially show you how to pull this information for a specific host. However, later in the post I will show you a helpful script that I put together to pull this information for multiple hosts based on host or cluster name.

The first thing to do is connect to your vCenter server.

Connect-VIServer vcenter.example.com

Next, get a specific host object and store it in the $VMHost variable.

$VMHost = Get-VMHost -Name esxi01.example.com

The CDP information is actually found within the NetworkSystem managed object of the HostConfigManager object. This can be accessed using the Get-View CmdLet as follows.

$NetSystem = Get-View $VMHost.ExtensionData.ConfigManager.NetworkSystem

If you pipe the $NetSystem object to the Get-Member CmdLet you should see something similar to this.

$NetSystem | Get-Member


   TypeName: VMware.Vim.HostNetworkSystem

Name                            MemberType Definition
----                            ---------- ----------
AddPortGroup                    Method     void AddPortGroup(VMware.Vim.HostPortGroupSpec portgrp)
AddServiceConsoleVirtualNic     Method     string AddServiceConsoleVirtualNic(string portgroup, VMware.Vim.HostVirtualNicSpec nic)
AddVirtualNic                   Method     string AddVirtualNic(string portgroup, VMware.Vim.HostVirtualNicSpec nic)
AddVirtualSwitch                Method     void AddVirtualSwitch(string vswitchName, VMware.Vim.HostVirtualSwitchSpec spec)
Equals                          Method     bool Equals(System.Object obj)
GetHashCode                     Method     int GetHashCode()
GetType                         Method     type GetType()
QueryNetworkHint                Method     VMware.Vim.PhysicalNicHintInfo[] QueryNetworkHint(string[] device)
RefreshNetworkSystem            Method     void RefreshNetworkSystem()

...
...

This displays all available methods and properties for this object. The method that we are going to use is QueryNetworkHint. To find out the arguments that this method requires you can run the method on its own.

$NetSystem.QueryNetworkHint

OverloadDefinitions
-------------------
VMware.Vim.PhysicalNicHintInfo[] QueryNetworkHint(string[] device)

We can see that the QueryNetworkHint method requires a single argument, which is an individual physical network device for the host. Helpfully, this information is readily available in our $VMHost variable from earlier. Running the following will list all physical devices for the specific host.

$VMHost.ExtensionData.Config.Network.Pnic

With these two pieces of information we are able to loop through each physical network device and run the QueryNetworkHint method.

foreach ($Pnic in $VMHost.ExtensionData.Config.Network.Pnic) {
    $NetSystem.QueryNetworkHint($Pnic.Device)
}

...

Device              : vmnic5
Subnet              : {3506, 3505}
Network             :
ConnectedSwitchPort : VMware.Vim.PhysicalNicCdpInfo
LldpInfo            :

Device              : vmnic6
Subnet              :
Network             :
ConnectedSwitchPort :
LldpInfo            :

Device              : vmnic7
Subnet              : {3506, 3505}
Network             :
ConnectedSwitchPort : VMware.Vim.PhysicalNicCdpInfo
LldpInfo            :

...

Looking at that output we can see that the information we are interested in is in the ConnectedSwitchPort property. I can expand the foreach loop as follows to get this information.

foreach ($Pnic in $VMHost.ExtensionData.Config.Network.Pnic) {
    $PnicInfo = $NetSystem.QueryNetworkHint($Pnic.Device)
    $PnicInfo.ConnectedSwitchPort
}


CdpVersion       : 2
Timeout          : 60
Ttl              : 137
Samples          : 21334
DevId            : N5K_1
Address          : 10.222.0.236
PortId           : Ethernet108/1/15
DeviceCapability : VMware.Vim.PhysicalNicCdpDeviceCapability
SoftwareVersion  : Cisco Nexus Operating System (NX-OS) Software, Version 7.0(7)N1(1)
HardwarePlatform : N5K-C5596UP
IpPrefix         : 0.0.0.0
IpPrefixLen      : 0
Vlan             : 1
FullDuplex       : True
Mtu              : 1500
SystemName       : N5K_1
SystemOID        : 1.3.6.1.4.1.9.12.3.1.3.1038
MgmtAddr         : 10.123.96.141
Location         :

CdpVersion       : 2
Timeout          : 60
Ttl              : 148
Samples          : 21334
DevId            : N5K_2
Address          : 10.222.0.235
PortId           : Ethernet108/1/15
DeviceCapability : VMware.Vim.PhysicalNicCdpDeviceCapability
SoftwareVersion  : Cisco Nexus Operating System (NX-OS) Software, Version 7.0(7)N1(1)
HardwarePlatform : N5K-C5596UP
IpPrefix         : 0.0.0.0
IpPrefixLen      : 0
Vlan             : 1
FullDuplex       : True
Mtu              : 1500
SystemName       : N5K_2
SystemOID        : 1.3.6.1.4.1.9.12.3.1.3.1038
MgmtAddr         : 10.123.96.142
Location         :

There is a lot of information available in this property, most of which I am not interested in. Also, it is not very helpful that I can’t tell from this output which physical device (e.g. vmnic0) that each of these blocks of information relate to. To tidy this up we can create a new PSCustomObject in the foreach loop and return only the information we want to see.

foreach ($Pnic in $VMHost.ExtensionData.Config.Network.Pnic) {
    $PnicInfo = $NetSystem.QueryNetworkHint($Pnic.Device)
    [PSCustomObject] @{
        'Device' = $Pnic.Device
        'DevId' = $PnicInfo.ConnectedSwitchPort.DevId
        'PortId' = $PnicInfo.ConnectedSwitchPort.PortId
    }
}

Device DevId                      PortId
------ -----                      ------
vmnic0
vmnic1
vmnic2
vmnic3
vmnic4
vmnic5 N5K_1                      Ethernet108/1/14
vmnic6
vmnic7 N5K_2                      Ethernet108/1/14

A Helper Script

Now that we understand how we can get this information via PowerCLI, I want to show you a helper script/function that I have put together. This script enables us to target specific hosts by hostname or cluster name and also allows us to filter which physical NICs we are interested in. The script is available on my GitHub.

Once you have the script downloaded you will need to connect to your vCenter server before running it.

Connect-VIServer -Server vcenter.example.com

Here are a few examples of how you can use this script, note that the script excludes any physical NICs which do not have CDP information available. First, lets get a single host’s CDP information.

.\Get-VMHostCDPInfo.ps1 -VMHost 'esxi01.example.com' | Format-Table

I am using Format-Table to present the large dataset in a more friendy way. Now lets get CDP information for all hosts in the cluster Cluster01.

.\Get-VMHostCDPInfo.ps1 -Cluster 'Cluster01' | Format-Table -GroupBy VMHost

   VMHost: esxi01.example.com

VMHost                Pnic   CdpVersion Timeout Ttl Samples DevId                      Address      PortId           DeviceCapability
------                ----   ---------- ------- --- ------- -----                      -------      ------           ----------------
esxi01.example.com    vmnic0          2      60 125  351248 N5K_5                      10.222.0.231 Ethernet109/1/30 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi01.example.com    vmnic1          2      60 124  351248 N5K_5                      10.222.0.231 Ethernet109/1/29 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi01.example.com    vmnic3          2      60 135  351249 N5K_5                      10.222.0.231 Ethernet109/1/27 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi01.example.com    vmnic4          2      60 163  351249 N5K_5                      10.222.0.230 Ethernet109/1/31 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi01.example.com    vmnic5          2      60 160  351249 N5K_5                      10.222.0.230 Ethernet109/1/30 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi01.example.com    vmnic7          2      60 160  351250 N5K_5                      10.222.0.230 Ethernet109/1/29 VMware.Vim.PhysicalNicCdpDeviceCapability


   VMHost: esxi02.example.com

VMHost                Pnic   CdpVersion Timeout Ttl Samples DevId                      Address      PortId           DeviceCapability
------                ----   ---------- ------- --- ------- -----                      -------      ------           ----------------
esxi02.example.com    vmnic0          2      60 143  346948 N5K_5                      10.222.0.231 Ethernet101/1/21 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi02.example.com    vmnic1          2      60 143  346948 N5K_5                      10.222.0.231 Ethernet101/1/20 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi02.example.com    vmnic3          2      60 165  346948 N5K_5                      10.222.0.231 Ethernet101/1/19 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi02.example.com    vmnic4          2      60 131  346947 N5K_5                      10.222.0.230 Ethernet101/1/21 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi02.example.com    vmnic5          2      60 170  346948 N5K_5                      10.222.0.230 Ethernet101/1/20 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi02.example.com    vmnic7          2      60 156  346948 N5K_5                      10.222.0.230 Ethernet101/1/19 VMware.Vim.PhysicalNicCdpDeviceCapability

In this example I also used the -GroupBy parameter of Format-Table to display the information grouped by each host. Now lets get CDP information for both esxi01.example.com and esxi02.example.com but filter the results to show just vmnic5 and vmnic7.

.\Get-VMHostCDPInfo.ps1 -VMHost 'esxi01.example.com', 'esxi02.exmple.com' -Vmnic 'vmnic5', 'vmnic7' | Format-Table -GroupBy VMHost

   VMHost: esxi01.example.com

VMHost                Pnic   CdpVersion Timeout Ttl Samples DevId                      Address      PortId           DeviceCapability
------                ----   ---------- ------- --- ------- -----                      -------      ------           ----------------
esxi01.example.com    vmnic5          2      60 155  436320 N5K_5                      10.222.0.231 Ethernet105/1/20 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi01.example.com    vmnic7          2      60 133  436320 N5K_5                      10.222.0.231 Ethernet105/1/18 VMware.Vim.PhysicalNicCdpDeviceCapability


   VMHost: esxi02.example.com

VMHost                Pnic   CdpVersion Timeout Ttl Samples DevId                      Address      PortId          DeviceCapability
------                ----   ---------- ------- --- ------- -----                      -------      ------          ----------------
esxi02.example.com    vmnic5          2      60 121  341221 N5K_5                      10.222.0.235 Ethernet102/1/7 VMware.Vim.PhysicalNicCdpDeviceCapability
esxi02.example.com    vmnic7          2      60 146  341222 N5K_5                      10.222.0.235 Ethernet102/1/6 VMware.Vim.PhysicalNicCdpDeviceCapability

And obviously you can use Select-Object to return only the columns that you require if you wish.

.\Get-VMHostCDPInfo.ps1 -VMHost 'esxi01.example.com' -Vmnic 'vmnic5', 'vmnic7' | Select-Object VMhost, Pnic, DevId, Address, PortId

VMHost  : esxi01.example.com
Pnic    : vmnic5
DevId   : N5K_5
Address : 10.222.0.231
PortId  : Ethernet105/1/20

VMHost  : esxi01.example.com
Pnic    : vmnic7
DevId   : N5K_5
Address : 10.222.0.231
PortId  : Ethernet105/1/18

Conclusion

I hope you have found this post and the helper script useful. It really did come in handy for me when gathering this information for our network team recently!

×