Pull PCI Bus information for Network Cards with PowerShell

Since its been about 3 months, I figured its about time for another post. A few weeks ago, a colleague of mine and I were discussing ways to identify which network cards were which when we build new Hyper-V cluster nodes. It can get a little nuts when you have 2 iSCSI networks, 1 Corp connection, and one connection that is tagged for VM’s on different VLAN’s, and a Heartbeat network.

We found that there is no real way to predict which NIC will be named “Local Area Connection”, “Local Area Connection 2”, Local Area Connection N …” and so on. However, poking around we did find that there is one thing in common across all of our servers. Assuming the NICS were all plugged into the switch in order, we could identify them by their PCI bus, device, and function ID as shown in the screenshot below.

image

Well that’s all good but how can we leverage that information and automate our network configuration for new cluster nodes. First, we need to come up with a standard. We know the PCI Bus information for each NIC in the server. Once we made that map, we can specify which NIC gets which IP Address.  Once you manually create that map, you still need a way to identify which NIC has what Bus information. Enter PowerShell.

This gets a little nuts because we have to piece this together from a couple different sources. The first bit of information that we need for each NIC is something called the PnPDeviceID. You can pull this wit WMI using the win32_networkAdapter class.

image

So what does this buy us. It turns out this is part of the path in the registry that stores the PCI bus information. Lets assume you store the PnPDeviced id in $deviceID. You can get the PCI Bus information with the following:

image

Those last 3 numbers that are circled in red are the BusID, DeviceID, and FunctionID. Note that this is for 2008 and 2008 R2. All I really need is those last 3 numbers so some regex trickery along with multi-variable assignment comes in pretty handy here.

image

So once we have that, we can put this all together in a couple functions

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
Function Get-NicBusFunctionID {
$adapters = get-wmiobject win32_networkadapter -filter "netenabled=true"

foreach ($adapter in $adapters) {
      
        $deviceId = $adapter.PnPDeviceID
        $locationInfo = (get-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Enum\$deviceID" `
                                          -name locationinformation).locationINformation
       
        $businfo = Resolve-PCIBusInfo -locationInfo $locationinfo
       
        new-object psobject -property @{
            "Name"        = $adapter.NetConnectionID;
            "MacAddress"  = $adapter.MacAddress
            "Index"       = $adapter.Index;
            "PCIBusID"      = $businfo.BusID;
            "PCIDeviceID"   = $businfo.DeviceID;
            "PCIFunctionID" = $businfo.FunctionID
        }
}

}

Function Resolve-PCIBusInfo {

param (
[parameter(ValueFromPipeline=$true,Mandatory=$true)]
[string]
$locationInfo
)
PROCESS {
[void]($locationInfo -match  "\d,\d,\d")
$busId,$deviceID,$functionID = $matches[0] -split ","

new-object psobject -property @{
          "BusID" = $busID;
          "DeviceID" = "$deviceID"
          "FunctionID" = "$functionID"
          }
}        
}


And a screenshot of how to use it

image

Comments (2) -

Scott Toenniessen 4/19/2010 5:04:59 PM

Hi,

This funtion is very helpful but noticed one thing, the expression which parses out the BUS, DEVICE, and FUNCTIONS IDs only returns a single character of those IDs.  On some systems these are 2 characters (especially the BUS ID).  I made this tweak to the Resolve-PCIBusInfo function to handle that:

Changed: [void]($locationInfo -match "\d,\d,\d")

To: [void]($locationInfo -match "[\d]*,[\d]*,[\d]*")

Would you be interested in exchanging links?

Comments are closed