The WMI COM library

This article was originally published in VSJ, which is now part of Developer Fusion.
“No man is an island, entire of itself; every man is a piece of the continent; a part of the main.”
John Donne (1572–1631)

Why am I quoting from a sermon given by a seventeenth century English poet? Sometimes the age of a concept doesn’t dull its relevance. Software is often viewed in isolation (as an “island”), but software that works with its environment can benefit in the same way that an isolated PC can benefit from connection to the Internet.

There are many mechanisms for obtaining information about the environment in which software runs. The registry, environment variables, and configuration files all have a role to play, and have all been present at least since the first 32-bit versions of Windows. Since Windows 2000 there has been a new option for obtaining system information called WMI (Windows Management Instrumentation). It is “a scalable system management infrastructure that uses a single consistent, standards-based, extensible, object-oriented interface”. As that definition would suggest, it can sometimes be quite indigestible too!

WMI Architecture

There are three main features of the WMI architecture:
  • Managed objects
  • Management applications.
  • WMI infrastructure
Managed objects are entities that provide information through WMI. In some cases, WMI can also be used to change properties on these entities. Managed objects may represent physical entities (computers, processors, disk drives) or software entities (processes, the registry, settings).

A management application is an application that accesses one or more managed objects. The term applies even when the application has no obvious management function, but just uses WMI to obtain some system information.

Finally, WMI infrastructure is the software that ships as part of the OS that provides support for managed objects and management applications and most importantly lets them discover and communicate with each other. The infrastructure also offers an eventing system and access to WMI objects located on other computers.

The Common Information Model (CIM)

In order to communicate, managed objects and managed applications must be able to exchange data in a format that each can understand. In principle, we would like to be able to build a management application that could display data from all the managed objects on the system without having to understand a plethora of proprietary data formats. This is where the Common Information Model (CIM) comes in.

This CIM is an object-oriented framework for WMI information. Like C/C++/C#, it defines classes which are instantiated as objects. These classes can define properties and methods, can be constructed using inheritance, and may be abstract. Methods may be static (i.e. not require a class instance in order to execute). The model itself is not tied to any single platform, and classes may be grouped in schema for specific platforms or applications.

CIM classes come in 3 flavours. Core classes (usually prefixed with a double-underscore “__”) provide basic functionality that will be used as a base for many other classes – such as the Namespace class, or the Event class. Common classes (usually prefixed with “CIM_”) are used to model the generic features of entities such as computers or disk drives. Extension classes (“Win32_” for Windows classes) provide implementation specific support for a specific environment or device type. Core and common classes are defined in the CIM schema, while Windows specific classes are in the Win32 schema.

The CIM also provides a facility called association which allows one class to indicate a relationship with another. For example, an association could be used to relate an object representing a Computer System to that representing its CPU.

Under Windows, objects are usually specified in a language called Managed Object Format (MOF). This is derived from IDL (Interface Definition Language, used in COM, the Component Object Model) but has extensions and modifications to support CIM.

The good news is that you don’t need a detailed knowledge of MOF (or CIM for that matter) unless you intend to create managed objects of your own.

WMI Object Paths

Each WMI namespace, class or object can be uniquely identified using its path. WMI paths are constructed much like UNC names – here’s an example:
\\Machine1\root\cimv2:Win32_
	LogicalDisk.DeviceID=”C:”
This string specifies an object with “DeviceID=”C:”” on “Machine1” in the “root\cimv2” namespace with class “Win32_LogicalDisk”.

Exploring WMI

So far we’ve taken a pretty theoretical look at what WMI is. With that little background however, the best thing to do now is dive in and start exploring.

A Windows PC doesn’t come pre-installed with a WMI browser that allows you to just dive in and look at the WMI tree (see sidebar “WMI Utilities” for the utilities that do come as standard), but if you have Microsoft Visual Studio .NET available, Microsoft supply a plug-in that allows you to do just that.

The download is called “Management (WMI) Extensions for Visual Studio .NET 2003 Server Explorer” (There is also a VS.NET 2002 version), and can be obtained from www.microsoft.com/downloads. The search string “WMI Extensions” should take you straight there.

Once installed, the Server Explorer view in VS is modified to include “Management Events” and “Management Classes” for each server. The “Management Classes” tree will include some classes by default, but more can be added by right-clicking on it and selecting “Add Class”.

Figure 1: Server Explorer in action
Figure 1: Server Explorer in action

The screenshot in Figure 1 shows Server Explorer in action. Here you can see that under “Management Classes” the “Disk Volumes” class has been expanded. Each node under the “Disk Volumes” class represents an instance of that class – an object. The object names in this case correspond to drive letters.

You can right-click the “Disk Volumes” class and select “Properties” to see the class definition – all of the properties the class supports – in the properties window. The same operation on an instance (e.g. “C:”) will show the actual property values for the object selected. Right at the bottom of the properties window, you can see the path of the object (or class) and its relationship to other classes.

If you right click on a class, you will see a list of the static methods, and right clicking on an object will give you access to the instance methods. Selecting a method will bring up a dialog with fields for all the parameter values and an invoke button (as shown in Figure 2) for the “chkdsk” method on my “C:”.drive.

Figure 2: Parameter values
Figure 2: Parameter values

The best way to understand the WMI Extension for Server Explorer is to spend some time exploring it. Beware though – method calls and property value changes through WMI (and thus from Server Explorer) will have a real effect on your system. Don’t change them unless you’re sure you want to!

WMI queries

Although the WMI Object Path system allows you to describe the path to an object, it is more usual to want to find either a specific object, or all instances of an object matching a specific set of criteria. For example, I might want to use WMI to find which drive letters correspond to real disks. Given such a task what we need is to be able to run queries in the WMI system.

WMI queries are constructed in WQL (WMI Query Language), which is essentially a subset of SQL. The following WQL string would correspond to the search for all used drive letters:

SELECT DeviceID FROM Win32_LogicalDisk
You can add conditions to such a query – for example to return only local disks using the NTFS filesystem:
ELECT DeviceID FROM Win32_LogicalDisk
	WHERE FileSystem=’NTFS’ and
	Description = ‘Local Fixed Disk’
Where my query has “DeviceID” you could put a “*” to get it to return all fields, or a list of the fields you wish to receive. Restricting the amount of information you request is usually a good idea however, as many classes have a lot of information in them and it all takes time to process!

In addition, WQL defines some new operations such as “ASSOCIATORS OF” (to find associated objects/classes) and “ISA” (for querying subclasses). See the MSDN topic “Querying with WQL” for more details.

When using WMI it is always worth checking the Microsoft WMI SDK to check that the classes, properties and methods you wish to use are implemented, supported on the OS that you are targeting, and are not being phased out – otherwise your queries may have fewer results than you expect!

Managed WMI

Query strings are used by applications to find the information they want – and unfortunately there is no place in Server Explorer to try them out, so at this point we’re going to write some code (although we could use WBEMTest – see sidebar “WMI Utilities”). The .NET framework has extensive support for WMI that handles a lot of the plumbing for you. It does add confusion to the terminology however, because .NET applications and classes are referred to as “Managed” which must not be confused with “Management” classes and objects in WMI. The code fragment shown below is a minimal function in C# to output the names of the installed drives to the console:
static void WriteInstalledDrives()
{
	string Query = “SELECT DeviceID
		FROM Win32_LogicalDisk”;
	ManagementObjectSearcher searcher =
		new ManagementObjectSearcher(
		Query);
	ManagementObjectCollection disks =
		searcher.Get();
	foreach (ManagementObject m in
		disks )
	{
		PropertyData DeviceID =
			m.Properties[“DeviceID”];
		Debug.Assert(null != DeviceID);
		Debug.Assert(DeviceID.Value is
			string);
		Console.WriteLine(
			DeviceID.Value as string );
	}
}
As you can see, even in this simple example it is necessary to check that the property you have asked for actually exists and whether the type is what was expected. I’ve done it here with Debug.Assert, but in production code the error handling required would be significant. Furthermore, the casting, error handling etc all serves to add complexity and obfuscate the meaning of the code. It would be nice if the .NET framework provided managed wrappers, but with a vast and growing number of WMI classes it could never keep up.

Help is at hand however from the WMI Extension for Server Explorer. If you have a .NET project open, you will get an extra option when right-clicking on a WMI class. This option is “Generate Managed Class” and it does exactly what the title suggests. It generates source code for a managed class that has managed properties and methods corresponding exactly to those in the WMI class. Where appropriate, property “set” will be implemented, as well as “get”, and will link back to the live WMI object. It also provides a few additional properties and methods to make it easier to use the class. The “GetInstance” method is the most important of these. Called with no parameters, it simply returns a list of all the objects of that class. There are several overloads however which allow you to limit the quantity of data returned, and specify partial query strings – as shown here:

using WMIExampleApplication.
	ROOT.CIMV2;
static void WriteLocalNTFSDrives()
{
	// SELECT DeviceID FROM
	// Win32_LogicalDisk WHERE
	// FileSystem=’NTFS’ and
	// Description = ‘Local Fixed Disk’
	LogicalDisk.LogicalDiskCollection
		lc = LogicalDisk.GetInstances(
		“FileSystem=’NTFS’ and
		Description = ‘Local Fixed
		Disk’”, new string[]
		{“DeviceID” } );
	foreach ( LogicalDisk l in lc )
	{
		Console.WriteLine(l.DeviceID);
	}
}
The code produced by Server Explorer is worth examining to see how it works in more detail, and there are plenty of comments in it to make this straightforward.

WMI Events

WMI events come in a number of flavours, according to the MSDN documentation:
  • Intrinsic events are generated by the WMI infrastructure when specified WMI data changes e.g. an object is added or removed, or a property changed.
  • Timer events are generated by the WMI infrastructure at a specific point in time. Technically these are actually just a special case of the Intrinsic event, but the WMI documentation separates it for unknown reasons…
  • Extrinsic events are generated by WMI Objects rather than by the infrastructure, and can correspond to any event of the objects choosing, e.g. an error condition in a server process or a notification that a disk has been removed from a drive.
All of these event types are accessed using WQL, and a management application must register with the WMI framework in order to actually receive the event. Event processing can be either synchronous or asynchronous, and once again the .NET framework provides for both scenarios.

Timer Events use the Win32_LocalTime or Win32_UTCTime class. These classes are automatically updated every second with the current time. The Win32_LocalTime definition in MOF looks like this:

class Win32_LocalTime :
	Win32_CurrentTime
{
	uint32 Day;
	uint32 DayOfWeek;
	uint32 Hour;
	uint32 Milliseconds;
	uint32 Minute;
	uint32 Month;
	uint32 Quarter;
	uint32 Second;
	uint32 WeekInMonth;
	uint32 Year;
};
Note that the Milliseconds property is marked in the documentation as not implemented.

A WQL Query to trigger an event at midday on Christmas Day would use the intrinsic __InstanceModificationEvent and would look something like this:

SELECT * FROM
	__InstanceModificationEvent WHERE
	TargetInstance ISA
		\”Win32_LocalTime\” AND
	TargetInstance.Month = 12 AND
		TargetInstance.Day = 25 AND
	TargetInstance.Hour = 12 AND
		TargetInstance.Minute = 0 AND
	TargetInstance.Second = 0
The code below shows how you would synchronously wait for this event to fire in a C# application (although would you ever want to block a thread until midday on Christmas Day?):
static void WaitForChristmasLunch()
{
	WqlEventQuery Query = new
		WqlEventQuery(
		“__InstanceModificationEvent”,
		“TargetInstance ISA
		\”Win32_LocalTime\”” + “AND
		TargetInstance.Month = 12” +
		“AND TargetInstance.Day = 25”
		+ “AND TargetInstance.Hour =
		12” + “AND
		TargetInstance.Minute = 0” +
		“AND TargetInstance.Second = 0”
		);
	ManagementEventWatcher Watcher =
		new ManagementEventWatcher(
		Query);
	ManagementBaseObject ev =
		Watcher.WaitForNextEvent();
	Console.WriteLine( “It’s Christmas “ +
		((ManagementBaseObject)ev[“TargetInstance”])
		[“Year”]);
	Watcher.Stop();
}
Note that we can reference the TargetInstance property of the __InstanceModificationEvent to get access to the object that changed, in this case to pull out the year. Note also the use of the ISA keyword so we pick up the event even if it is caused by a class that inherited from Win32_LocalTime.

The ManagementEventWatcher class in .NET also provides for receiving events asynchronously by adding an event handler to Watcher.EventArrived and invoking Watcher.Start.

This example focuses specifically on testing for time, but the __InstanceModificationEvent can be used to detect changes in the data of any object. Furthermore, there are many other intrinsic events (defined in the CIM) that can detect the creation and deletion of classes, objects and namespaces, method invocation etc. Extrinsic events are simply extension classes that inherit from __ExtrinsicEvent and are used in exactly the same way.

WMI Events can be explored and tested in the Server Explorer extension for WMI by right clicking on the “Management Events” node and selecting the “Add Event Query” option. When the event occurs, you will receive notification in the Visual Studio output pane showing the affected object(s) and their properties.

Conclusions

Having introduced WMI and shown how to perform basic WMI operations in C#, I’m going to leave you with a few examples of classes and properties you might find useful in the real world. These can be found in the table below, and are intended as a small taster of the information you can get at through WMI.

Useful classes and their properties

Class Notes
Win32_ScheduledJobs The Windows “Scheduled Tasks” mechanism exposed to the user through the control panel
Win32_OperatingSystem Provides access the version and serial numbers of the Windows installation
Win32_Service Represents a Windows Service, and can be used to start, stop or pause it in addition to obtaining status information.
Win32_NetworkAdapter-Configuration Can be used to obtain status, IP addresses and MAC addresses of network connections
Win32_USBControllerDevice Used to get information about connected USB devices
Win32_PerfFormattedData_PerfOS_Processor Performance data on the processor – great for dashboard style utilities
Win32_Battery Battery Status Information

I hope that I have shown that WMI is a powerful and (thanks to .NET) easy to use tool to enable your applications to interact more richly with the environment around them.


Ian Stevenson has been developing Windows software professionally for 10 years, in areas ranging from WDM device drivers through to rapid-prototyping of enterprise systems. Ian currently works as a consultant in the software industry.

WMI Utilities

There are two useful little utilities included with Windows that allow you to interact with WMI. WBEMTest is a GUI that allows you to interact fully with WMI classes and objects, but its user interface is not very user friendly and it is best used for testing rather than exploring(WBEM stands for Web-Based Enterprise Management and was the name used for WMI during its early life). WinMgmt is a command line utility that allows registration and un-registration of the WinMgmt service which provides WMI services on Windows. It can also be used to backup and restore WMI information. Both utilities can be run from the command line.

You can also use the “net” command to stop, start, pause or continue the WinMgmt service, which can be useful if you manage to upset the WMI Infrastructure for some reason. (e.g. “net pause winmgmt”). This can happen when you accidentally set up a WMI Event that fires very frequently and causes an application (like Visual Studio) to become non-responsive.

You might also like...

Comments

About the author

Ian Stevenson United Kingdom

Ian Stevenson has been developing Windows software professionally for 10 years, in areas ranging from WDM device drivers through to rapid-prototyping of enterprise systems. Ian currently works a...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Walking on water and developing software from a specification are easy if both are frozen.” - Edward V Berard