Exploring NDIS’s WMI classes
Getting fancy with PowerShell and WMI
Last time we got our feet wet with a simple PowerShell script to query Ethernet MAC addresses. It looked easy, but of course, it requires you to know the magic WMI class name "MSNdis_EthernetCurrentAddress". How do you go about discovering other interesting WMI classes? Once again, PowerShell to the rescue:
PS > Get-WmiObject -Namespace root\wmi -List | Where-Object {$_.name -Match "MSNdis" } | Sort-Object
This command will list all of the NDIS WMI classes available on your system. (Try it out!) There are quite a few, but you can bring order to chaos by classifying them into several main categories:
Class name prefix | Description |
MSNdis_80211 | WiFi wireless miniports |
MSNdis_Ethernet | Ethernet (or Ethernet-emulating) miniports |
MSNdis_AtmMSNdis_FddiMSNdis_TokenRing | Very old media types (ATM, FDDI, and Token Ring) |
MSNdis_Co | CoNDIS drivers |
MSNdis_NotifyMSNdis_Status | WMI Events (another great feature, which we'll talk about later) |
MSNdis_Wmi | Data structures used as parameters to methods (which we'll talk about right now) |
Let's pick one of the classes at random, and see what we can do with it. How about MSNdis_ReceiveScaleCapabilities? From its name, we infer that it reads the adapter's RSS capabilities. Recall that many of NDIS's WMI classes are translated directly from the underlying OID — knowing this will help us quite a bit as we start to decode the WMI class. A quick search on MSDN turns up OID_GEN_RECEIVE_SCALE_CAPABILITIES, which uses an NDIS_RECEIVE_SCALE_CAPABILITIES structure. Keep that documentation in mind as we explore the WMI class.
Now let's get our hands dirty:
PS > $Adapters = Get-WmiObject -Namespace root\wmi -Class MSNdis_ReceiveScaleCapabilities
PS > $Adapters[6]
Active : True
InstanceName : BitBlaster 2000 Ethernet Adapter
Well that's… disappointing. We got back an array of instances (one for each network adapter), but the only real properties are the name a boolean Active flag. I know that this network adapter supports RSS, so where is all the RSS info hiding?
It turns out that many NDIS classes don’t expose their information directly. Instead, they require you to invoke a WMI method on the class to retrieve the information. In order to find the method, let's use the PowerShell Get-Member cmdlet:
PS > Get-WmiObject -Namespace root\wmi -Class MSNdis_ReceiveScaleCapabilities | Get-Member
TypeName: System.Management.ManagementObject#root\wmi\MSNdis_ReceiveScaleCapabilities
Name MemberType Definition
---- ---------- ----------
WmiQueryReceiveScaleCapabilities Method System.Management.ManagementBaseObject WmiQueryReceiveScaleCapabilitie...
Active Property System.Boolean Active {get;set;}
InstanceName Property System.String InstanceName {get;set;}
__CLASS Property System.String __CLASS {get;set;}
__DERIVATION Property System.String[] __DERIVATION {get;set;}
__DYNASTY Property System.String __DYNASTY {get;set;}
__GENUS Property System.Int32 __GENUS {get;set;}
__NAMESPACE Property System.String __NAMESPACE {get;set;}
__PATH Property System.String __PATH {get;set;}
__PROPERTY_COUNT Property System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH Property System.String __RELPATH {get;set;}
__SERVER Property System.String __SERVER {get;set;}
__SUPERCLASS Property System.String __SUPERCLASS {get;set;}
ConvertFromDateTime ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime ScriptMethod System.Object ConvertToDateTime();
There's a lot of stuff in there, but you can see that one member is a method named WmiQueryReceiveScaleCapabilities. Let's dig into it:
PS > Get-WmiObject -Namespace root\wmi -Class MSNdis_ReceiveScaleCapabilities | Get-Member -Name WmiQueryReceiveScaleCapabilities | Format-List
TypeName : System.Management.ManagementObject#root\wmi\MSNdis_ReceiveScaleCapabilities
Name : WmiQueryReceiveScaleCapabilities
MemberType : Method
Definition : System.Management.ManagementBaseObject
WmiQueryReceiveScaleCapabilities(System.Management.ManagementObject#MSNdis_WmiMethodHeadr Header)
So it's a function that takes an MSNdis_WmiMethodHeader as input, and returns another WMI class as output. You'll find that this is the general pattern for NDIS's WMI methods — fortunately, the MSNdis_WmiMethodHeader is basically boilerplate; you don't have to fret over how to create each one. Let's create a little helper function to do that boilerplate for us:
$NDIS_WMI_METHOD_HEADER_REVISION_1 = 1
$NDIS_WMI_OBJECT_TYPE_METHOD = 0x02
$NDIS_SIZEOF_WMI_METHOD_HEADER_REVISION_1 = 0xffff
function Get-NdisObjectHeader
{
param(
$revision = $NDIS_WMI_METHOD_HEADER_REVISION_1,
$type = $NDIS_WMI_OBJECT_TYPE_METHOD,
$size = $NDIS_SIZEOF_WMI_METHOD_HEADER_REVISION_1
)
$hdr = ([wmiclass]'root\wmi:MSNdis_ObjectHeader').CreateInstance()
$hdr.Revision = $revision
$hdr.Type = $type
$hdr.Size = $size
return $hdr
}
function Get-NdisWmiHeader
{
param($timeout = 5)
$whdr = ([wmiclass]'root\wmi:MSNdis_WmiMethodHeader').CreateInstance()
$whdr.Header = Get-NdisObjectHeader
$whdr.PortNumber = 0
$whdr.NetLuid = 0
$whdr.Padding = 0
$whdr.RequestId = 0
$whdr.Timeout = $timeout
return $whdr
}
Now that we can conjure up the input parameter, we can return to the task of executing our WMI method. This part should be easy:
PS > $whdr = Get-NdisWmiHeader
PS > $RSS = $Adapters[6].WmiQueryReceiveScaleCapabilities($whdr)
PS > $RSS
RssCaps : System.Management.ManagementBaseObject
PS > $RSS.RssCaps
CapabilitiesFlags : 184550145
Header : System.Management.ManagementBaseObject
NumberOfInterruptMessages : 1
NumberOfReceiveQueues : 2
Ah-hah! Now that looks like a promising result! (You didn't really have doubts that we'd figure it out eventually, did you?)
The last mystery remaining is the number 184550145. But if you remember what we said earlier — WMI classes are based on OID requests — you'll check the documentation for NDIS_RECEIVE_SCALE_CAPABILITIES. And indeed, each field listed above corresponds to a field in that driver structure. So you can conclude that you should use the flags documented there to decode the CapabilitiesFlags. In this case, decimal 184550145 is hex 0x0B000301, which corresponds to NDIS_RSS_CAPS_MESSAGE_SIGNALED_INTERRUPTS | NDIS_RSS_CAPS_CLASSIFICATION_AT_ISR | NDIS_RSS_CAPS_USING_MSI_X | NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV4 | NDIS_RSS_CAPS_HASH_TYPE_TCP_IPV6 | NdisHashFunctionToeplitz.
Now that you're armed with the techniques above, you have the chops to explore the remaining NDIS WMI classes. Next time we'll talk about one more cool trick you can do with WMI.
Comments
Anonymous
February 07, 2012
This rocks my socks.Anonymous
February 19, 2013
and simply get the ndis driver version through wmi ?Anonymous
March 08, 2013
For NDIS contract version, you can use gwmi -namespace rootwmi -class MSNdis_DriverVersion The result is an integer packed as per OID_GEN_DRIVER_VERSION, with 0xFF00 masking out the major version, and 0x00FF masking out the minor version. For the driver-reported version number, look at MSNdis_VendorDriverVersion. Note that if you're targeting Windows 8 / Windows Server 2012, you can alternatively use Get-NetAdapter and pick out MSFT_NetAdapter.DriverMajorNdisVersion , DriverVersionString, and MajorDriverVersion. (These are a little easier to work with.)Anonymous
June 23, 2014
This driver does not seem to be installed on windows 7 all request to MSNdis are answered with Error.. Can you Advise ? 10x.Anonymous
June 24, 2014
I'm quite sure that Windows 7 includes MSNdis support, as I wrote this blog post using Windows 7. What error are you getting? Can you try on a different PC?Anonymous
March 13, 2015
Hello! Could you briefly translate this simple query (WmiQueryReceiveScaleCapabilities) from PowerShell to C# ? I'm trying to use GetMethodParameters/InvokeMethod but I'm stuck.. (I'm not a master in C#..), probably for you it will be easy peasy Appreciate your help. BobAnonymous
March 14, 2015
The comment has been removedAnonymous
March 14, 2015
@ Bob Unfortunately, porting the code to C# is both outside my expertise and the scope of this blog. I can only offer you a guess. I believe that "GetMethodParameters" is a red herring -- that lets you reflect on the methods. But in this case, you already know the method parameters, so you don't need to do reflection. Instead, take a look at ManagementClass.CreateInstance. The example at the bottom of this page shows how ot create an instance of a class and set its member fields: msdn.microsoft.com/.../system.management.managementclass.createinstance(v=vs.110).aspx . Except you won't need to call Put on it as in the example. Instead, use the object instance as an input to ManagementClass.InvokeMethod.Anonymous
March 15, 2015
Okay, looks like you got the answer on stackoverflow: stackoverflow.com/.../powershell-c-sharp-wmi-correct-filling-input-object-for-invokemethodAnonymous
March 15, 2015
@Jeffery I just wanted to share link to stackoverflow, but you were first :] ps Thanks for this NDIS blog [this is the best source of NDIS knowledge], and waiting for more!