Collect VMware ESX Host PCI Device Information

Whenever you need to install a new box with ESX, there’s the struggle with matching physical ports to VMware devices. Which network adapter becomes vmnic0?, Which hostbus adapter becomes vmhba1?, etc. Especially when you have a lot of network adapters this can be confusing and you can’t connect to the device over the network unless you have the right patching and physical switch port configuration. For the record my last box had 10 nics!

First thing to understand is that it’s important to know the PCI bus numbering, because ESX numbers the devices in ascending PCI bus number order. The network adapter with the lowest PCI number will become eth0/vmnic0.

How to do this:

  • Use the hardware vendor’s specification sheet and learn which expansion slot has which PCI bus number. If you have a network adapter with multiple ports, the lowest port number will be the first device detected. From here sort everything in ascending PCI bus number order.
  • Use the VMware provided tool “vmkvsitools“. Go to the console and issue the command “vmkvsitools lspci“. This command returns a list of all PCI devices in your system, equal to just running the “lspci” command, but adds the VMware device name at the end of each line.

    vmkvsitools also displays PCI numbers in decimal format.

If you are only concerned about network adapters, you could also use “esxcfg-nics“. Go to the console and issue the command “esxcfg-nics -l“. This command generates a list of network adapters and their PCI number.

Whenever I need to install a new type of hardware I use the vmkvsitools method to document my host before it’s going into production. There’s nothing more important than having your documentation 100% in place. I know it’s quite some work to document everything, but whenever a problem arises you don’t need to search for information and this relieves stress J

The PowerCLI way

Since VMware is moving away from the Service Console I was wondering how I could use PowerCLI to retrieve that information for me.

For the host bus adapter this can be achieved quite easily using this one-liner

Get-VMHost -Name "esx01" | Get-VMHostHba | Select Pci, Device, Model

For the network adapters you could use something similar using the Get-VMHostNetworkAdapter cmdlet instead.

Get-VMHost -Name "esx01"| Get-VMHostNetworkAdapter –Physical

However the PowerCLI object that is returned doesn’t contain the PCI information. So we have to do this one the SDK way.

The SDK way

To retrieve the full API object we need to use the Get-View cmdlet. By exploring the HostSystem object in the vSphere API reference, we learn that the required information can be found in the .Config.Network.Pnic property. This results in the following one-liner

Get-View -ViewType HostSystem -Filter @{"Name" = "esx01"} | %{$_.Config.Network.Pnic | Select Pci, Device}

Of course you could also use the API object to report on the host bus adapter. This information can be found in the .Config.StorageDevice.HostBusAdapter property, which leads to this onliner

Get-View -ViewType HostSystem -Filter @{"Name" = "esx01"} | %{$_.Config.StorageDevice.HostBusAdapter | Select Pci, Device, Model}

The PowerCLI 4.1 way

In PowerCLI version 4.1 there are two new cmdlets called New-VIProperty and Remove-VIProperty. Together with the new ExtensionData property, which exposes the API object that corresponds to the returned PowerCLI object, these cmdlets open new possibilities. Using these new cmdlets you can access the API object the PowerCLI way. Have a look at Lucd’s post PowerCLI 4.1 brings the New-VIProperty cmdlet for more information on using these new cmdlets.

Remember when I wanted to access the PCI information on the network adapter earlier? This information wasn’t exposed by the PowerCLI object. Using the New-VIProperty cmdlet I can now expose this information myself. Let’s have a look at the code:

New-VIProperty -Name Pci -ObjectType PhysicalNic -ValueFromExtensionProperty 'pci'
Get-VMHost -Name "esx01"| Get-VMHostNetworkAdapter –Physical | Select Pci, DeviceName

The Full Report

Besides network- and host bus adapters we could also report on other PCI devices using the API object. PCI information is stored in the .Hardware.PciDevice property. The following one-liner would generate a full report on all PCI devices similar to using the “lspci” command in the service console

Get-View -ViewType HostSystem -Filter @{"Name" = "esx01"} | %{$_.Hardware.PciDevice | Select Id, VendorName, DeviceName}

However this doesn’t show the associated VMware device names like the “vmkvsitools lspci” command. I’ve created the following function to return the host’s PCI devices and their associated ESX device names.

function Get-VMHostPciDevice {
<#
.SYNOPSIS
  Returns the ESX(i) host's PCI Devices
.DESCRIPTION
  This function returns the ESX(i) host's PCI devices en their associated ESX devices
.NOTES
  Author:  Arnim van Lieshout
.PARAMETER VMHost
  The ESX(i) host entity for which the PCI devices should be returned
.EXAMPLE
  PS> Get-VMHostPciDevice -VMHost (Get-VMHost "esx01")
.EXAMPLE
  PS> Get-VMHost "esx01" | Get-VMHostPciDevice
#>

	Param (
	[parameter(valuefrompipeline = $true, mandatory = $true,
	HelpMessage = "Enter an ESX(i) host entity")]
	[VMware.VimAutomation.Types.VIObject[]]$VMHost)

	Begin {
# Create PCI class array
		$PciClass = @("Unclassified device","Mass storage controller","Network controller","Display controller","Multimedia controller","Memory controller","Bridge","Communications controller","Generic system peripheral","Input device controller","Docking station","Processor","Serial bus controller","Wireless controller","Intelligent controller","Satellite communications controller"," Encryption controller","Signal processing controller")
	}

	Process {
		if($VMHost) {
			$VMHostView = $VMHost | Get-View
		}
		else {
			$VMHostView = $_ | Get-View
		}

# Get the PCI Devices
		$VMHostView | % {
			$PciDevices = @()
			foreach ($dev in $_.Hardware.PciDevice) {
				$objDevice = "" | Select Pci, ClassName, VendorName, DeviceName, EsxDeviceName
				$objDevice.Pci = $dev.Id
				$objDevice.ClassName = $PciClass[[int]($dev.ClassId/256)]
				$objDevice.VendorName = $dev.VendorName
				if ($dev.DeviceName -notmatch "Unknown") {
					$objDevice.DeviceName = $dev.DeviceName
				}
				$PciDevices += $objDevice
			}

# Find associated ESX storage devices
			foreach ($hba in $_.Config.StorageDevice.HostBusAdapter) {
				$PciDevices | ? {$_.Pci -match $hba.Pci} | % {$_.EsxDeviceName = "["+$hba.device+"]"}
			}

# Find associated ESX network devices
			foreach ($nic in $_.Config.Network.Pnic) {
				$PciDevices | ? {$_.Pci -match $nic.Pci} | % {$_.EsxDeviceName = "["+$nic.device+"]"}
			}
		}
	}

	End {
    	$PciDevices| Sort-Object -Property Pci
	}
}

PCI Device Classes

Instead of the PCI id, I’ve included the PCI class name. The PCI id is a 2byte id, where the first byte refers to the PCI class and the second byte refers to the PCI subclass. The following table shows the PCI classes which I defined in the $PCIClass array.

00  Unclassified device 
01  Mass storage controller 
02  Network controller 
02  Display controller 
04  Multimedia controller 
05  Memory controller 
06  Bridge
07  Communication controller 
08  Generic system peripheral 
09  Input device controller 
0a  Docking station 
0b  Processor 
0c  Serial bus controller 
0d  Wireless controller 
0e  Intelligent controller 
0f  Satellite communications controller 
10  Encryption controller
11  Signal processing controller 

Related posts:

  1. PowerCLI: Match VM and Windows harddisks – Part 2 Tweet This is a follow up on a post I did a couple of weeks ago to create a mapping table between Windows- and VMware hard disks. In another previous...
  2. List HBA WWPNs and LUNs using Powershell Tweet Lately I’m moving around my VMs and storage luns between my ESX clusters a lot to accomplish a complete redesign of my Virtual Infrastructure. At some point I got...
  3. Installing ESX 4.0 on VMware Fusion Tweet If you love VMware you have to love Apple and if you love ESX4.0 you have to love a Mac. Well, at least I know I do. Both companies...
  4. Reconnect ESX hosts using PowerShell Tweet This week I ran into problems with vCenter server and almost all of my VMs were orphaned in vCenter. To resolve this issue I needed to disconnect/connect each ESX...
  5. VMware ESX(i) 3.5 Update4 released Tweet VMware has released ESX(i) 3.5 update4. Do not forget to read the release notes here or you can go to the download page here While going through the release notes...

3 Comments on “Collect VMware ESX Host PCI Device Information”

  1. #1 JimPeluso
    on Jul 23rd, 2010 at 11:54 am

    Great set of scripts. I also enjoyed reading your explanations and the evolution of PowerCLI. It’s amazing to see that VMWare listens to the community. the New-VIProperty is an excellent example of that.

  2. #2 Steffen
    on Jul 23rd, 2010 at 6:10 pm

    Great posts, just what I was searching for yesterday. Thanks a lot!

  3. #3 Ivan Talley
    on Sep 15th, 2010 at 9:24 pm

    Thanks for this info. I’ve been looking for something like this for some time. Just became aware of CDP info as a possibility from an instructor last night but we’re not using Cisco equipment. This is exactly what I needed!

Leave a Comment