06 January 2013

Determine VMs' Uplink vmnic on vSwitch with PowerCLI

Ever have the need to determine which uplink vmnic on which vSwitch a VM is using?  We have, too.  And, we have relied on traditional hardware level info in the past to get such info:  get with the network team and have them tell us on what physical switch port they see the MAC address of the given VM, and then correlate that with the VMHost's vmnic.  Straight forward, fast, easy, and self-service.  Not.

The standard ways described elsewhere on the web are to use esxtop on a VMHost or resxtop from somewhere with the vCLI installed (press "n" once in [r]esxtop).  But, wouldn't it be nice if there was a way without having to enable SSH on a host, or SSH'ing to a vMA appliance (if you do not already have the vCLI installed).  Maybe, say, with PowerCLI, which everybody has installed (right?).  Oh, wait -- there is:  Get-EsxTop.

Here is a function that uses Get-EsxTop to get, for VMs on a VMHost, their vSwitch and vmnic uplink information:
<#  .Description
Function to retrieve Netports' (portgroup ports') client, uplink info, vSwitch, etc. info.  Includes things like VMKernel ports and Management uplinks.
    Author:  vNugglets.com -- Nov 2012
    .Outputs
    PSObject
#>
function Get-VNUplinkNic {
    param(
        ## the VMHost DNS name whose VMs' uplink info to get (not VMHost object name -- so, do not use wildcards)
        [parameter(Mandatory=$true)][string]$VMHostToCheck_str,
        ## PSCredential to use for connecting to VMHost; will prompt for credentials if not passed in here
        [System.Management.Automation.PSCredential]$CredentialForVMHost_cred
    ) ## end param

    $strThisVMHostName = $VMHostToCheck_str

    ## check if VMHost name given is responsive on the network; if not, exit
    if (-not (Test-Connection -Quiet -Count 3 -ComputerName $strThisVMHostName)) {
        Write-Warning "VMHost '$strThisVMHostName' not responding on network -- not proceeding"; exit}

    ## set/get the credential to use for connecting to the VMHost (get if not already passed as param)
    $credToUseForVMHost = if ($CredentialForVMHost_cred) {$CredentialForVMHost_cred} else 
        {$host.ui.PromptForCredential("Need credentials to connect to VMHost", "Please enter credentials for '$strThisVMHostName'", $null, $null)}

    ## connect to the given VIServer (VMHost, here)
    $oVIServer = Connect-VIServer $strThisVMHostName -Credential $credToUseForVMHost

    ## if connecting to VMHost failed, write warning and exit
    if (-not $oVIServer) {Write-Warning "Did not connect to VMHost '$strThisVMHostName' -- not proceeding"; exit}

    ## array with PortID to vSwitch info, for determining vSwitch name from PortID
    ## get vSwitch ("PortsetName") and PortID info, not grouped
    $arrNetPortEntries = (Get-EsxTop -Server $strThisVMHostName -TopologyInfo NetPort).Entries

    ## calculated property for vSwitch name
    $hshVSwitchInfo = @{n="vSwitch"; e={$oNetportCounterValue = $_; ($arrNetPortEntries | ?{$_.PortId -eq $oNetportCounterValue.PortId}).PortsetName}}

    ## get the VM, uplink NIC, vSwitch, and VMHost info
    Get-EsxTop -Server $strThisVMHostName -CounterName NetPort | select @{n="VMName"; e={$_.ClientName}},TeamUplink,$hshVSwitchInfo,@{n="VMHostName"; e={$_.Server.Name}}

    Disconnect-VIServer $strThisVMHostName -Confirm:$false
} ## end function

The comments should pretty much explain what is happening, if it is not already clear.  Once you have defined the function, you can use it like:

PS vNuggs:\> Get-VNUplinkNic -VMHostToCheck somehost

Need credentials to connect to VMHost
Please enter credentials for 'somehost'
User: root
Password for user root: *************

VMName         TeamUplink   vSwitch     VMHostName
----------     ----------   -------     ----------
Management     n/a          vSwitch0    somehost
vmk1           vmnic0       vSwitch0    somehost
vmk0           vmnic0       vSwitch0    somehost
dev0-vm0       vmnic0       vSwitch0    somehost
dev0-vm12323   vmnic5       vSwitch0    somehost
dev0-vm2       vmnic5       vSwitch0    somehost
dev0-vm32237   vmnic4       vSwitch1    somehost
dev0-vm9       vmnic8       vSwitch1    somehost
...

Pretty handy.  And, it does not meet up with the same limitation that you might face with [r]esxtop -- that you can only get uplink info for the top X number of VMs on a host, where X is the number of rows available for display in your console session.  So, you can get the uplink info for all VMs on the host.  Then, you can sort/filter as needed -- VMs on a given uplink is a nice to know, for example.

There you go:  another tasty vNugglet.

Postscript:  After writing this function, and in the process of composing this post, I found a VMware Communities thread (http://communities.vmware.com/thread/341604) that does also provide a portion of this goodness, but that thread did not include the cool sauce for getting the vSwitch info -- so, at least that part is new -- yeah-hooey.