Getting VMKernel Adapter Details in vCenter with PowerCLI

ESXi hosts use VMKernel ports (vmk ports) to send and receive network traffic. Just as a regular, physical NIC, these virtual adapters have several properties that at some point we may need to know or gather for troubleshooting, design or configuration purposes. While it is perfectly possible to look for the vmk details using the vSphere Client, it is a tedious, relatively time-consuming task, besides, there is no easy way to consolidate and export this information. Furthermore, there is no PowerCLI cmdlet to make it more straightforward, there is not a Get-VmkPort or similar command we can take advantage of.

Today I am going to share a somewhat basic script that makes getting vmk ports details a fairly simple task. Let's go over it step by step. The process described here assumes an existing PowerCLI connection to a vCenter server, see Connect-ViServer cmdlet's help for more details.

First, we will get the list of hosts and save it in a variable. The vmk ports are actually a property of the hosts so it makes sense to get the parent objects first. If you need to exclude some hosts you can always add a filter to the line below, using the Where-Object cmdlet.

$vHosts = Get-VMHost | Sort-Object Name

Notice that I am using Sort-Object to get a list sorted by name. This is not required but recommended if the hosts names have some sequential, logical order.

Now we are going to add a foreach loop to iterate through the list of hosts in the vHosts variable. Here is where we get the list of all vmk ports associated with each host. Remember I mentioned vmk's are a property of the VMHost object, in fact, to be more specific, they are contained inside a VMHost property (VirtualNic) which is why we need to expand the VirtualNic property, using the ExpandProperty parameter of the Select-Object cmdlet.

foreach ($vHost in $vHosts) {
    $VMHost = $vHost.Name
    $vmks = $vHost | Get-VMHostNetwork | Select-Object -ExpandProperty VirtualNic | Sort-Object Name
}

The two lines inside the foreach loop above accomplish two things:

  1. Save the name of each host in a variable with name VMHost. Here we use the Name property of the vHost object (ESXi host) to get the host name.
  2. For each ESXi host (or vHost in the vHosts variable) we get the list of vmk ports using the Get-VMHostNetwork cmdlet piped to the vHost object. Then the output is piped to Select-Object to specifically get only the VirtualNic property, but at the same time we "unwrap" VirtualNic to get its contents -the actual vmk objects- by adding the ExpandProperty parameter. Finally, we sort the vmk's by name in order to get a more organized output.

Now we will need to add a nested foreach loop inside the existing or main loop to process each host's vmk ports, which are stored in the vmks variable. This will build a new object out of the vmk properties, for this purpose we will use the PSCustomObject type accelerator. In every iteration, the code below will run against each object (VMHost) stored in the vHosts variable and at the same time, the second or nested loop will run against each one of the objects (VMKernel ports) stored in the vmks variable, which at the end will generate a list of all vmk's in the connected vCenter server. The following lines of code correspond to the second / nested loop only.

foreach ($vmk in $vmks) {
    $VmkObjct = [pscustomobject] @{'VMHost' = $vmk.VMHost
                                   'DeviceName' = $vmk.DeviceName
                                   'IP' = $vmk.IP
                                   'DhcpEnabled' = $vmk.DhcpEnabled
                                   'SubnetMask' = $vmk.SubnetMask
                                   'Mac' = $vmk.Mac                      
                                   'VMotionEnabled' = $vmk.VMotionEnabled                        
                                   'ManagementTrafficEnabled' = $vmk.ManagementTrafficEnabled
                                   'MTU' = $vmk.Mtu}
}

Adding [pscustomobject] before a hash table results in the creation of a new object with each key value pair becoming a property name and value for such object. Based on this, it can be easily inferred that DeviceName, IP, DhcpEnabled, SubnetMask, Mac, VMotionEnabled, ManagementTrafficEnabled and MTU are the properties of the new object.

Output: Now that the new vmk objects have been created, we need to either display them in the console, or export them to a file. To get a proper output, it is important to keep in mind that each iteration of the nested or second loop will create an object, therefore, each time the loops run, something has to be done with the output, otherwise it will be lost forever as it will be overwritten during the next iteration.

My suggestion to capture the output is to use either Export-Csv or Write-Output at the end of the nested loop, right before the foreach closing curly bracket. The full commands would be the following:

$VmkObjct | Export-Csv -Path ~\Documents\vmk.csv -Append -NoTypeInformation
$VmkObjct | Write-Output

Both lines can be added to the script if you want to see the output onscreen and export it to a csv file as well. Otherwise, choose whichever works best for you and get rid of the other line. Remember to edit the path of the output file as needed when applicable. Notice the Append parameter in line 1, it is required because we are looping through the objects instead of using the pipeline. Without Append the output file would only have one row with the last vmk processed since the whole file is overwritten during the next iteration. Append tells PowerShell to keep adding rows immediately after the last one, as opposed to completely replacing the csv.

Again, the code below is only the second / nested loop. This will run for each host.

foreach ($vmk in $vmks) {
    $VmkObjct = [pscustomobject] @{'VMHost' = $vmk.VMHost
                                   'DeviceName' = $vmk.DeviceName
                                   'IP' = $vmk.IP
                                   'DhcpEnabled' = $vmk.DhcpEnabled
                                   'SubnetMask' = $vmk.SubnetMask
                                   'Mac' = $vmk.Mac                  
                                   'VMotionEnabled' = $vmk.VMotionEnabled                     
                                   'ManagementTrafficEnabled' = $vmk.ManagementTrafficEnabled
                                   'MTU' = $vmk.Mtu}

    $VmkObjct | Export-Csv -Path ~\Documents\vmk.csv -Append -NoTypeInformation
    Write-Output $VmkObjct
}

Finally, here is the complete script.

$vHosts = Get-VMHost | Sort-Object Name

#Begin first loop
foreach ($vHost in $vHosts) {
    $VMHost = $vHost.Name
    $vmks = $vHost | Get-VMHostNetwork | Select-Object -ExpandProperty VirtualNic | Sort-Object Name
    
    #Begin second / nested loop
    foreach ($vmk in $vmks) {
        $VmkObjct = [pscustomobject] @{'VMHost' = $vmk.VMHost
                                       'DeviceName' = $vmk.DeviceName
                                       'IP' = $vmk.IP
                                       'DhcpEnabled' = $vmk.DhcpEnabled
                                       'SubnetMask' = $vmk.SubnetMask
                                       'Mac' = $vmk.Mac
                                       'VMotionEnabled' = $vmk.VMotionEnabled
                                       'ManagementTrafficEnabled' = $vmk.ManagementTrafficEnabled
                                       'MTU' = $vmk.Mtu}
    
    $VmkObjct | Export-Csv -Path ~\Documents\vmk.csv -Append -NoTypeInformation    
    Write-Output $VmkObjct
    }#Closing curly bracket for second / nested loop

}#Closing curly bracket for first loop

This is what the output looks like in the console. Due to the amount of properties that each vmk has, they are displayed as a list.

vmk output

And this is a snapshot of the csv file.

vmk csv output

Now we can work with the output, the csv format is especially useful for reporting purposes once converted to .xls / .xlsx. Excel filters allow to easily sort the objects (rows) and filter them by host or any other property (column).

That is all it takes to build a vmk list with PowerCLI. I hope you find this post useful. Feel free to leave comments and questions below and thanks for reading this far.

The source code for this post is available in my GitHub repository.