Mladen Prajdić Blog

Blog about stuff and things and stuff. Mostly about SQL server and .Net

Find only physical network adapters with WMI Win32_NetworkAdapter class

WMI is Windows Management Instrumentation infrastructure for managing data and machines. We can access it by using WQL (WMI querying language or SQL for WMI). One thing to remember from the WQL link is that it doesn't support ORDER BY. This means that when you do SELECT * FROM wmiObject, the returned order of the objects is not guaranteed. It can return adapters in different order based on logged-in user, permissions of that user, etc… This is not documented anywhere that I've looked and is derived just from my observations.

To get network adapters we have to query the Win32_NetworkAdapter class. This returns us all network adapters that windows detect, real and virtual ones, however it only supplies IPv4 data. I've tried various methods of combining properties that are common on all systems since Windows XP.

The first thing to do to remove all virtual adapters (like tunneling, WAN miniports, etc…) created by Microsoft. We do this by adding WHERE Manufacturer!='Microsoft' to our WMI query. This greatly narrows the number of adapters we have to work with. Just on my machine it went from 20 adapters to 5. What was left were one real physical Realtek LAN adapter, 2 virtual adapters installed by VMware and 2 virtual adapters installed by VirtualBox.

If you read the Win32_NetworkAdapter help page you'd notice that there's an AdapterType that enumerates various adapter types like LAN or Wireless and AdapterTypeID that gives you the same information as AdapterType only in integer form. The dirty little secret is that these 2 properties don't work. They are both hardcoded, AdapterTypeID to "0" and AdapterType to "Ethernet 802.3". The only exceptions I've seen so far are adapters that have no values at all for the two properties, "RAS Async Adapter" that has values of AdapterType = "Wide Area Network" and AdapterTypeID = "3" and various tunneling adapters that have values of AdapterType = "Tunnel" and AdapterTypeID = "15". In the help docs there isn't even a value for 15. So this property was of no help.

Next property to give hope is NetConnectionId. This is the name of the network connection as it appears in the Control Panel -> Network Connections. Problem is this value is also localized into various languages and can have different names for different connection. So both of these properties don't help and we haven't even started talking about eliminating virtual adapters. Same as the previous one this property was also of no help.

Next two properties I checked were ConfigManagerErrorCode and NetConnectionStatus in hopes of finding disabled and disconnected adapters. If an adapter is enabled but disconnected the ConfigManagerErrorCode = 0 with different NetConnectionStatus. If the adapter is disabled it reports ConfigManagerErrorCode = 22. This looked like a win by using (ConfigManagerErrorCode=0 or ConfigManagerErrorCode=22) in our condition. This way we get enabled (connected and disconnected adapters).

Problem with all of the above properties is that none of them filter out the virtual adapters installed by virtualization software like VMware and VirtualBox.

The last property to give hope is PNPDeviceID. There's an interesting observation about physical and virtual adapters with this property. Every virtual adapter PNPDeviceID starts with "ROOT\". Even VMware and VirtualBox ones. There were some really, really old physical adapters that had PNPDeviceID starting with "ROOT\" but those were in pre win XP era AFAIK. Since my minimum system to check was Windows XP SP2 I didn't have to worry about those.

The only virtual adapter I've seen to not have PNPDeviceID start with "ROOT\" is the RAS Async Adapter for Wide Area Network. But because it is made by Microsoft we've eliminated it with the first condition for the manufacturer. Using the PNPDeviceID has so far proven to be really effective and I've tested it on over 20 different computers of various configurations from Windows XP laptops with wireless and bluetooth cards to virtualized Windows 2008 R2 servers. So far it always worked as expected. I will appreciate you letting me know if you find a configuration where it doesn't work.

Let's see some C# code how to do this:

ManagementObjectSearcher mos = null;
// WHERE Manufacturer!='Microsoft' removes all of the
// Microsoft provided virtual adapters like tunneling, miniports, and Wide Area Network adapters.
mos = new ManagementObjectSearcher(@"SELECT *
FROM Win32_NetworkAdapter
WHERE Manufacturer != 'Microsoft'"
);

// Trying the ConfigManagerErrorCode and NetConnectionStatus variations
// proved to still not be enough and it returns adapters installed by
// the virtualization software like VMWare and VirtualBox
// ConfigManagerErrorCode = 0 -> Device is working properly. This covers enabled and/or disconnected devices
// ConfigManagerErrorCode = 22 AND NetConnectionStatus = 0 -> Device is disabled and Disconnected.
// Some virtual devices report ConfigManagerErrorCode = 22 (disabled) and some other NetConnectionStatus than 0
mos = new ManagementObjectSearcher(@"SELECT *
FROM Win32_NetworkAdapter
WHERE Manufacturer != 'Microsoft'
AND (ConfigManagerErrorCode = 0
OR (ConfigManagerErrorCode = 22 AND NetConnectionStatus = 0))"
);

// Final solution with filtering on the Manufacturer and PNPDeviceID not starting with "ROOT\"
// Physical devices have PNPDeviceID starting with "PCI\" or something else besides "ROOT\"
mos = new ManagementObjectSearcher(@"SELECT *
FROM Win32_NetworkAdapter
WHERE Manufacturer != 'Microsoft'
AND NOT PNPDeviceID LIKE 'ROOT\\%'"
);
// Get the physical adapters and sort them by their index.
// This is needed because they're not sorted by default
IList<ManagementObject> managementObjectList = mos.Get()
.Cast<ManagementObject>()
.OrderBy(p => Convert.ToUInt32(p.Properties["Index"].Value))
.ToList();

// Let's just show all the properties for all physical adapters.
foreach (ManagementObject mo in managementObjectList)
{
foreach (PropertyData pd in mo.Properties)
Console.WriteLine(pd.Name + ": " + (pd.Value ?? "N/A"));
}

 

That's it. Hope this helps you in some way.

Legacy Comments


Scott R.
2010-11-04
re: Find only physical network adapters with WMI Win32_NetworkAdapter class
Mladen,

Great post on gathering info on network adapters (NICs).

I agree that the process of identifying the subset of NICs you would like to view or collect is challenging.

Some time ago, I was exploring gathering NIC info via WMI. There is a property in the Win32_NetworkAdapter WMI class called Speed that is supposed to show the configured network speed of the NIC (such as 1 Gbps, 100 Mbps, 54 Mbps for some WiFi, etc.). On older OS versions (Windows Server 2003 and earlier, Windows XP and earlier), the Speed column in the Win32_NetworkAdapter WMI class was present but not populated.

If this network speed info is of interest, there are two solutions:

- Newer OS versions (Windows Server 2008 and later, Windows Vista and later) now populate the Speed column – no extra work needed. Note that even on these newer OS versions, the Speed column is only populated for active (connected) NICs. There are still some NICs with no value in the Speed column.

- On older OS versions, your code could sense when the Speed column is empty, and optionally query two other undocumented WMI classes for the speed info:
o MSNdis_EnumerateAdapter
o MSNdis_LinkSpeed

When I used this method in code, I would read all entries of both of these WMI classes into arrays in memory, and then do array lookups for each item in the Win32_NetworkAdapter that I was processing to get the related Speed column value. It would be cool to have a SQL join option in WSQL (WMI SQL) for WMI classes (instead of this table lookup approach), but I don’t think that exists yet.


To easily query basic info on NICs and other WMI classes, I often use the WMIC command line utility or the WBEMTEST utility. For example, to display all NIC names and speeds for the local system:

WMIC NIC Get SystemName, Name, Speed

WMIC can also be used to remotely query other systems (if you have the required permissions) – for example:

WMIC /Node:Server1,Server2 NIC Get SystemName, Name, Speed

I’m sure there are comparable WMI queries possible from PowerShell – I just haven’t explored them yet. Since WMIC is installed with the OS (even on older OS versions), it may be more available than PowerShell on older OS versions for local uses.


Scott R.

Mladen Prajdic
2010-11-04
re: Find only physical network adapters with WMI Win32_NetworkAdapter class
hey Scott!
thanx. and good info on the speeds! didn't know that.

Aleksandar
2010-11-19
re: Find only physical network adapters with WMI Win32_NetworkAdapter class
Mladen,

you can achieve the same with this PowerShell code:

PS> $query = "SELECT * FROM Win32_NetworkAdapter WHERE Manufacturer != 'Microsoft' AND NOT PNPDeviceID LIKE 'ROOT\\%'"
PS> Get-WmiObject -Query $query | Sort index

You can put all that in one line, too. ;)

Scott,

here is equivalent PowerShell code:

gwmi win32_networkadapter | select systemname,name,speed
gwmi win32_networkadapter -cn server1,server2 | select systemname,name,speed

(gwmi is an alias for Get-WmiObject cmdlet, and cn is an alias for ComputerName parameter)

Mladen Prajdic
2010-11-19
re: Find only physical network adapters with WMI Win32_NetworkAdapter class
@Aleksandar:
Thanx for the PowerShell script! I'm sure it will come in handy.

doug
2010-12-02
re: Find only physical network adapters with WMI Win32_NetworkAdapter class
I don't have a machine with VMware installed...but have you tried querying win32_networkadapterconfiguration where ipenabled = true?

Mladen Prajdic
2010-12-02
re: Find only physical network adapters with WMI Win32_NetworkAdapter class
yes i have. that returns virutal adapters as well. also IIRC it doesn't show disabled physical adapters.