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:
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
##################################################################################################
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
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.
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.
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 |
Ok, you didn't mention NIC Teaming before.
Try something like this
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
Hi Luc,
Is it complicated to modify the above to query an ESXi host with a vDS configured?
VDS is a completely different story.
I'll have a look.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
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.
There is a line missing, this should work
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
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
I tried to do the += with table and collector as a collection found from another script.
Will try a straight pipe out to csv.
A straight pipe worked, thank you.
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.
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
No chance you have one up your sleeve?
If not, thats ok.
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
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
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
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.