faherne_CTI
Enthusiast
Enthusiast

Collect vDS Portgroup, VMNIC and CDP information

Hi,

I found an awesome PowerCLI function that works fantastically, but I'd really like to get a slightly modified table output that included the following:

| VMHost | PortGroup Name | VMNIC ID | VLAN No. | Switch Port ID |  Switch Port ID Connected |  Switch Name | Switch VLAN IP |

The following article gives me almost all of the above except:

  • The vDS Portgroup Name
  • The vDS PortGroup VLAN number
  • Take into account that a VMNIC may be a member of more than 1 portgroup

https://www.jonathanmedd.net/2013/07/obtaining-cdp-info-via-powercli.html

I did find a different PowerCLI script that pulls the vDS portgroup VLAN, but doesn't include the configured PortGroup Name, and doesn't take into account that a VMNIC may be a member of more than one PortGroup: Cisco Discovery Protocol

Here's my slightly modified code, but I do not know how to integrate the 3 bullet points above:

####################################################################################

function Get-VMHostNetworkAdapterCDP {
<#
.SYNOPSIS
Function to retrieve the Network Adapter CDP info of a vSphere host.

.DESCRIPTION
Function to retrieve the Network Adapter CDP info of a vSphere host.

.PARAMETER VMHost
A vSphere ESXi Host object

.INPUTS
System.Management.Automation.PSObject.

.OUTPUTS
System.Management.Automation.PSObject.

.EXAMPLE
PS> Get-VMHostNetworkAdapterCDP -VMHost ESXi01,ESXi02

.EXAMPLE
PS> Get-VMHost ESXi01,ESXi02 | Get-VMHostNetworkAdapterCDP
#>

[CmdletBinding()][OutputType('System.Management.Automation.PSObject')]

Param
(

[parameter(Mandatory=$true,ValueFromPipeline=$true)]
[ValidateNotNullOrEmpty()]
[PSObject[]]$VMHost
)

begin {

$ErrorActionPreference = 'Stop'
Write-Debug $MyInvocation.MyCommand.Name
$CDPObject = @()
}

process{

try {
foreach ($ESXiHost in $VMHost){

if ($ESXiHost.GetType().Name -eq "string"){

try {
$ESXiHost = Get-VMHost $ESXiHost -ErrorAction Stop
}
catch [Exception]{
Write-Warning "VMHost $ESXiHost does not exist"
}
}

elseif ($ESXiHost -isnot [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl]){
Write-Warning "You did not pass a string or a VMHost object"
Return
}

$ConfigManagerView = Get-View $ESXiHost.ExtensionData.ConfigManager.NetworkSystem
$PNICs = $ConfigManagerView.NetworkInfo.Pnic

foreach ($PNIC in $PNICs){

$PhysicalNicHintInfo = $ConfigManagerView.QueryNetworkHint($PNIC.Device)

if ($PhysicalNicHintInfo.ConnectedSwitchPort){

$Connected = $true
}
else {
$Connected = $false
}

$hash = @{
MangementAddress = $PhysicalNicHintInfo.ConnectedSwitchPort.MgmtAddr
Switch = $PhysicalNicHintInfo.ConnectedSwitchPort.DevId
Connected = $Connected
PortId = $PhysicalNicHintInfo.ConnectedSwitchPort.PortId
NIC = $PNIC.Device
VMHost = $ESXiHost.Name
#HardwarePlatform = $PhysicalNicHintInfo.ConnectedSwitchPort.HardwarePlatform
#SoftwareVersion = $PhysicalNicHintInfo.ConnectedSwitchPort.SoftwareVersion
}
$Object = New-Object PSObject -Property $hash
$CDPObject += $Object
}
}
}
catch [Exception] {

throw "Unable to retrieve CDP info"
}
}
end {

Write-Output $CDPObject
}
}

$MyCluster = "<Insert Clustername>"

Get-Cluster $MyCluster| Get-VMHost | Get-VMHostNetworkAdapterCDP | Select VMHost,NIC,PortId,Connected,Switch,MangementAddress | Export-Csv .\$($MyCluster)"_CDP_Info.csv" -NoTypeInformation -UseCulture

##################################################################################################

0 Kudos
20 Replies
LucD
Leadership
Leadership

I'm not sure I understand what you are trying to do here.
A pNIC is connected to a Switch (VSS or VDS), not a portgroup.
The only link you can establish is to list all portgroups on that switch.


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

0 Kudos
faherne_CTI
Enthusiast
Enthusiast

A VMNIC is a label for a pNIC, right? e.g. vmnic0

I'm looking to create a table in terms of the active and standby VMNICs/pNICs assigned to each portgroup in a vDS, and then correlate this information with the CDP info pulled from the physical switches and their ports attached to the pNICs.

0 Kudos
faherne_CTI
Enthusiast
Enthusiast

E.g.

- An ESXi host has 8 pNICs tagged vmnic0-7.

- Each ESXi Host is connected to 2 x physical switches, 4 ports to Switch01 (odd numbered0), 4 ports to Switch-02 (even numbered)

- Each host has a single vDS assigned with the 8 pNICs.

- Each port group has 4 x Portgroups:

1. Mgmt:

Active: vmnic0, Standby: vmnic1

2. vMotion:

Active: vmnic1, Standby: vmnic0

3. VM Network

Active: vmnic2,3,4,5

4. NFS

Active: vmnic6, Standby: vmnic7

- I need to display this information to the Networks team, so that they can correlate the different ESXi network traffic to their Cisco switch ports.

0 Kudos
faherne_CTI
Enthusiast
Enthusiast

I'm looking to create a table as follows:

| VMHost | PortGroup Name | VMNIC ID | VLAN No. | Switch Port ID |  Switch Port ID Connected |  Switch Name | Switch VLAN IP  |

| ESX01    | Mgmt                     | vmnic0      | VLAN10    | Eth100/1/01      |  Connected                           | Switch01         |  192.168.10.1    |

| ESX01    | Mgmt                     | vmnic1      | VLAN10    | Eth101/1/01      |  Connected                           | Switch02         |  192.168.11.1    |

| ESX01    | vMotion                 | vmnic1      | VLAN20    | Eth101/1/02      |  Connected                           | Switch02         |  192.168.20.1    |

| ESX01    | vMotion                 | vmnic0      | VLAN20    | Eth100/1/02      |  Connected                           | Switch01         |  192.168.21.1    |

| ESX01    | VM network           | vmnic2      | VLAN30    | Eth100/1/03      |  Connected                           | Switch01         |  192.168.30.1    |

| ESX01    | VM network           | vmnic3      | VLAN30    | Eth101/1/03      |  Connected                           | Switch02         |  192.168.31.1    |

| ESX01    | VM network           | vmnic4      | VLAN30    | Eth100/1/04      |  Connected                           | Switch01         |  192.168.30.2    |

| ESX01    | VM network           | vmnic5      | VLAN30    | Eth101/1/04      |  Connected                           | Switch02         |  192.168.31.2    |

| ESX01    | NFS                       | vmnic6      | VLAN40    | Eth100/1/05      |  Connected                           | Switch01         |  192.168.40.1    |

| ESX01    | NFS                       | vmnic7      | VLAN40    | Eth101/1/05      |  Connected                           | Switch01         |  192.168.41.1    |

0 Kudos
LucD
Leadership
Leadership

Ok, you didn't mention NIC Teaming before.
Try something like this

Get-Cluster -PipelineVariable cluster |

Get-VMHost -PipelineVariable esx |

ForEach-Object -Process {

   Get-VirtualPortGroup -VMHost $esx -Standard -PipelineVariable pg |

   ForEach-Object -Process {

   @($pg.ExtensionData.Spec.Policy.NicTeaming.NicOrder.ActiveNic) +

   @($pg.ExtensionData.Spec.Policy.NicTeaming.NicOrder.StandbyNic) +

   @($pg.VirtualSwitch.ExtensionData.Spec.Policy.NicTeaming.NicOrder.ActiveNic) +

   @($pg.VirtualSwitch.ExtensionData.Spec.Policy.NicTeaming.NicOrder.StandbyNic) |

   Sort-Object -Unique |

   ForEach-Object -Process {

   $netSys.QueryNetworkHint($_) |

   ForEach-Object -Process {

   $hint = $_

   $hint.ConnectedSwitchPort |

   ForEach-Object -Process {

   New-Object PSObject -Property ([ordered]@{

   Cluster = $cluster.Name

   VMHost = $esx.Name

   Switch = $pg.VirtualSwitch.Name

   PortGroup = $pg.Name

   VLanId = $pg.VLanId

   Vmnic = $hint.Device

   IP = $_.Address

   SwitchPort = $_.PortId

   SwitchPortVLanId =  $_.VLan

   })

   }

   }

   }

   }

}


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

0 Kudos
faherne_CTI
Enthusiast
Enthusiast

Hi Luc,

Is it complicated to modify the above to query an ESXi host with a vDS configured?

0 Kudos
LucD
Leadership
Leadership

VDS is a completely different story.
I'll have a look.


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

0 Kudos
asgraffius
Contributor
Contributor

LucD,

When attempting to run this as a script it has an error on the line:

$netSys.QueryNetworkHint ($_)  |

stating it cannot call a method on a null-valued expression. I don't see where the $netSys variable is defined prior to this line may be the issue.

0 Kudos
LucD
Leadership
Leadership

There is a line missing, this should work

Get-Cluster -PipelineVariable cluster |

Get-VMHost -PipelineVariable esx |

ForEach-Object -Process {

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

    Get-VirtualPortGroup -VMHost $esx -Standard -PipelineVariable pg |

    ForEach-Object -Process {

        @($pg.ExtensionData.Spec.Policy.NicTeaming.NicOrder.ActiveNic) +

        @($pg.ExtensionData.Spec.Policy.NicTeaming.NicOrder.StandbyNic) +

        @($pg.VirtualSwitch.ExtensionData.Spec.Policy.NicTeaming.NicOrder.ActiveNic) +

        @($pg.VirtualSwitch.ExtensionData.Spec.Policy.NicTeaming.NicOrder.StandbyNic) |

        Sort-Object -Unique |

        ForEach-Object -Process {

            $netSys.QueryNetworkHint($_) |

            ForEach-Object -Process {

                $hint = $_

                $hint.ConnectedSwitchPort |

                ForEach-Object -Process {

                    New-Object PSObject -Property ([ordered]@{

                            Cluster          = $cluster.Name

                            VMHost           = $esx.Name

                            Switch           = $pg.VirtualSwitch.Name

                            PortGroup        = $pg.Name

                            VLanId           = $pg.VLanId

                            Vmnic            = $hint.Device

                            IP               = $_.Address

                            SwitchPort       = $_.PortId

                            SwitchPortVLanId = $_.VLan

                        })

                }

            }

        }

    }

}


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

0 Kudos
Gr33nEye
Enthusiast
Enthusiast

@LucD ,

Is it possible to add an export to CSV.

 

I tried and am going from error to error.

Tags (1)
0 Kudos
LucD
Leadership
Leadership

You can 'pipe' everything to an Export-Csv after the last closing curly brace.

What errors are you getting?


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

0 Kudos
Gr33nEye
Enthusiast
Enthusiast

I tried to do the += with table and collector as a collection found from another script.

Will try a straight pipe out to csv.

0 Kudos
Gr33nEye
Enthusiast
Enthusiast

A straight pipe worked, thank you.

@LucD 

You mentioned that a vDS is different. Is there a vDS version of the script?

I tried to remove the -standard from the Get-VirtualPortGroup but it doesn't look like it did anything

 

*Edit* did try to replace it with Get-VDPortgroup, but that did not work.

0 Kudos
LucD
Leadership
Leadership

Like I stated earlier in this thread, a VDS uses a different logic, which requires a different script.


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

0 Kudos
Gr33nEye
Enthusiast
Enthusiast

No chance you have one up your sleeve?

 

If not, thats ok.

0 Kudos
LucD
Leadership
Leadership

No, I didn't, but I got intrigued 🙄
Just came up with this quick-and-dirty snippet.
Give it a try

 

Get-Cluster -PipelineVariable cluster |
    Get-VMHost -PipelineVariable esx |
    ForEach-Object -Process {
        $netSys = Get-View -Id $esx.ExtensionData.ConfigManager.NetworkSystem
        Get-VDSwitch -VMHost $esx -PipelineVariable vdsw |
            ForEach-Object -Process {
                $obj = [ordered]@{
                    Cluster          = $cluster.Name
                    VMHost           = $esx.Name
                    Switch           = $vdsw.Name
                    Portgroup        = ''
                    Uplink           = ''
                    pNIC             = ''
                    TeamType         = ''
                    Device           = ''
                    IP               = ''
                    DevId            = ''
                    SwitchPort       = ''
                    SwitchPortVLanId = ''
                }
                $uplinkTab = @{}
                Get-VDPort -VDSwitch $vdsw -Uplink |
                    where { $_.ExtensionData.Connectee.ConnectedEntity -eq $esx.ExtensionData.MoRef } |
                    ForEach-Object -Process {
                        $uplinkTab.Add($_.ExtensionData.Config.Name, $_.ExtensionData.Connectee.NicKey)
                    }
                    Get-VDPortgroup -VDSwitch $vdsw -PipelineVariable vdpg | where { -not $_.IsUplink } |
                        ForEach-Object -Process {
                            $obj['Portgroup'] = $vdpg.Name
                            if ($vdpg.ExtensionData.Config.DefaultPortConfig.UplinkTeamingPolicy.UplinkPortOrder.ActiveUplinkPort) {
                                $vdpg.ExtensionData.Config.DefaultPortConfig.UplinkTeamingPolicy.UplinkPortOrder.ActiveUplinkPort |
                                    ForEach-Object -Process {
                                        $hint = $netSys.QueryNetworkHint($uplinkTab[$_])
                                        $obj['Uplink'] = $_
                                        $obj['pNIC'] = $uplinkTab[$_]
                                        $obj['TeamType'] = 'Active'
                                        $obj['Device'] = $hint.Device
                                        $hint.ConnectedSwitchPort | ForEach-Object -Process {
                                            $obj['DevId'] = $_.DevId
                                            $obj['IP'] = $_.Address
                                            $obj['SwitchPort'] = $_.PortId
                                            $obj['SwitchPortVLanId'] = $_.VLan
                                            New-Object -TypeName PSObject -Property $obj
                                        }
                                    }
                                }
                                if ($vdpg.ExtensionData.Config.DefaultPortConfig.UplinkTeamingPolicy.UplinkPortOrder.StandbyUplinkPort) {
                                    $vdpg.ExtensionData.Config.DefaultPortConfig.UplinkTeamingPolicy.UplinkPortOrder.StandbyUplinkPort |
                                        ForEach-Object -Process {
                                            $hint = $netSys.QueryNetworkHint($uplinkTab[$_])
                                            $obj['Uplink'] = $_
                                            $obj['pNIC'] = $uplinkTab[$_]
                                            $obj['TeamType'] = 'Standby'
                                            $obj['Device'] = $hint.Device
                                            $hint.ConnectedSwitchPort | ForEach-Object -Process {
                                                $obj['DevId'] = $_.DevId
                                                $obj['IP'] = $_.Address
                                                $obj['SwitchPort'] = $_.PortId
                                                $obj['SwitchPortVLanId'] = $_.VLan
                                                New-Object -TypeName PSObject -Property $obj
                                            }
                                        }
                                    }
                                } 
                            }
                        }

 

 


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

0 Kudos
Gr33nEye
Enthusiast
Enthusiast

Looks awesome,

$hint.Device

 Seems to reference the vNic uplink, not the actual physical Switch.

 

I did try below, but i came up blank.

$hint.ConnectedSwitchPort | ForEach-Object -Process {
$obj['Device'] = $_.Device
and
$obj['Device'] =  $hint.ConnectedSwitchPort.Device
0 Kudos
LucD
Leadership
Leadership

Not sure what the issue is.
The teaming (active and standby) on VDS is expressed with the Uplinks.
I use a table to link the Uplinks to the pNICs on each ESXi node.
This seems to work for me


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

0 Kudos
Gr33nEye
Enthusiast
Enthusiast

oh the teaming bit is fine.

I thought the idea was to get the full cdp info from each vnic. It only gets the physical connected switch IP, but not the name of the switch. Having both the IP and names makes it allow easier to sort.

0 Kudos