You are on page 1of 28

An In-Depth Look at WMI and Instrumentation, Part I

By Klaus Salchner

Introduction
WMI stands for Windows Management Instrumentation and, as the name indicates, is about
managing your IT infrastructure. Applications are used to solve specific business needs or
ease existing pains in an enterprise. One step in the process of acquiring enterprise-wide
applications is the cost benefit analysis. What are the costs of acquiring this application and
what are the benefits. Costs are distinguished between one-time costs and ongoing costs.
Even though one-time costs can be quite high, it is really the ongoing costs which are under
high scrutiny. Ongoing costs typically exceed the one-time costs by far and hit IT budgets
hard. This involves training IT staff to have the necessary skills to install, maintain and
troubleshoot the application. This also involves proactively monitoring the application so
certain SLA's (Service Level Agreements) are met. Almost every IT department needs to
guarantee certain service levels to their internal customers. This is important to them; they
need to know that they can rely on the fact that the application is available and functioning
when required. The last thing you want is to introduce a new finance system and, when you
need to book receivables, it is not available and your business is impacted. This also
involves troubleshooting applications when they are down and getting it up within
guaranteed time frames. Application downtimes hit the organization twofold. For one, the
business is impacted because it cannot perform a certain function. On the other hand, you
have expensive resources looking for the root cause like a needle in a hay stack.
Applications are still very hard to troubleshoot; 90% of the time is spent identifying the root
cause and the remaining 10% fixing it. Often it happens that IT staff is fixing the symptoms
of a problem instead of the root cause, mostly due to the fact that it is hard to identify the
real root cause.

This is not a new challenge. But "maintainability", which encompasses all the things stated
above, is an important application characteristic in today's world. Every IT department has a
say when it comes to acquiring new enterprise applications. And besides performance and
scalability, they will inquire in more and more detail about how easy it is to maintain your
application, how easy it is to get proactively notified about application issues with suggested
resolutions, and how easy it is to troubleshoot your application.

Windows Management Instrumentation to the rescue

This is where WMI comes into play. It provides a consistent programmatic access to
management information in the enterprise. It uses the typical provider and consumer
concept where you have on one side components providing this management information
while on the other side management applications can subscribe and consume it.
Management applications also don't have to go out and find these providers and their
information. WMI provides a WMI store which gives access to all the providers and all the
classes and objects these providers provide. This makes it very easy for management
applications to discover all the information available and then read and consume this
management information. WMI is Microsoft's implementation of WEBM (Web-Based
Enterprise Management) Initiative. WBEM defines a set of standards deployed to provide a
unified management of enterprise computing environments. You can find more information
about WBEM here .
WBEM itself uses a standardized data model to describe manageable objects like systems,
applications, services, networks, etc. This is the Common Information Model (CIM) and you
can find more information about it here. The WMI data model is extending the CIM data
model. WMI is a component of the Windows OS and is included out-of-the-box on Windows
2000, Windows XP and Windows 2003. It is located in the "windows\system32\wbem"
folder. It can be downloaded for earlier versions of Windows from here (with a number of
other WMI tools) . WMI also provides a rich programming interface including VB, C++,
scripting languages and the .NET framework itself.

A WMI architecture overview


The WMI architecture consists of three layers. Layer one contains the managed objects and
providers which provide rich management information. Managed objects are logical or
physical components in the enterprise which are managed. Providers are COM or .NET
components which monitor the managed objects and expose real time information about
them to WMI. Any managed application can provide one or multiple managed objects and a
provider by providing the necessary components so information is available to WMI.

Layer two is the WMI infrastructure which is provided by the Windows OS itself. The WMI
infrastructure consists of the "Windows Management Instrumentation" service and the WMI
repository (store). The Windows Management Instrumentation service is the intermediary
between the providers, the consumers and the WMI store. Providers can place information
through it into the WMI repository, consumers can query the WMI store for available
information, and the WMI service can pass information directly between providers and
consumers.

Layer three consists of the management applications, the applications which are interacting
with WMI to find information about managed objects. Management applications gather
information to analyze it and provide a comprehensive and accurate view of what is
happening to these managed objects. Operators can use this raw or processed information
to make decisions, take actions and resolve items. Microsoft's implementation of such a
management application is Microsoft Operations Manager 2005 (which we cover later in the
article).

A look at the WMI data model


Each managed object is represented through a WMI class stored in the WMI schema. A WMI
class can have properties, system properties, methods and qualifiers. System properties are
defined by the WMI infrastructure, for example the class name, the list of classes this class
is inherited from, etc. The properties are information you can store in an instance of this
class. The methods are actions you can perform on a class instance. Methods have in-
parameters and out-parameters, the method return code being the out-parameter with the
name "ResultValue". Qualifiers provide qualifying information about the class, the property
or the method (each has a list of qualifiers). For example "Abstract" for abstract classes,
"Constructor" to mark a method as constructor, "Destructor" to mark a method as
destructor, "In" and "Out" to mark method parameters as in or out, etc. A list of standard
and WMI specific qualifiers can be found here.
This is exactly the same as in the .NET framework with the exception that you define these
WMI classes through WMI and store them in the WMI repository. You can group classes
together into namespaces, like your namespaces in .NET. Each provider typically creates
its own namespace, for example "root\enterpriseminds". The root namespace is called
"Root" and all other namespaces are children of it. Each namespace can have one or
multiple classes and child namespaces. The picture on the left shows a sample (please
note this is an abbreviated view using the sample application attached to the second part
of this article to demonstrate this namespace and class hierarchy).

On top you see the Root namespace which has two classes. System classes always start
with two underscores. The Root namespace has aspnet, cimv2, default and directory child
namespaces. In the picture you can see that the cimv2 namespace has two system classes
followed with a number of Win32 classes implemented by it.

The class Win32_DefragAnalysis, for example, provides a defrag analysis and returns all
the information back to the WMI consumer. The namespace cimv2 is where you find all
classes provided by Windows itself. All classes provided by IIS are in the microsoftiisv2
namespace. You can create your own namespaces as needed, e.g. root\mycompany.

Like in .NET, you cannot instantiate abstract classes. All other classes can have class
instances, actual objects which hold data (information). Class instances can be static or
dynamic. Static class instances are stored in the WMI repository and the WMI service
queries it directly from the WMI store. Dynamic class instances are provided in real time by
underlying providers. Classes which provide dynamic class instances are marked with the
Dynamic qualifier and also have a Provider qualifier which specifies the name of the
provider. Providers (or rather, the information about providers) are stored in the WMI store
as static class instances of the class __Win32Provider. The provider named in a Provider
qualifier needs to have a __Win32Provider class instance so WMI knows the class ID and
other related information it needs to communicate with the dynamic provider. Almost all
classes defined in the cimv2 and microsoftiisv2 namespace are dynamic.

WMI provides class instances (objects) and events. Both are defined as WMI classes in the
WMI repository. The difference is that consumers have to actively query for class instances
while they can subscribe to events; as soon as an event is available the consumer gets
notified about it. More on that later in this article.

The .NET framework support for WMI


The .NET framework has comprehensive support for WMI but still has limitations. The
System.Management namespace provides the classes needed to interact with WMI. The
types in this namespace are used to query for WMI classes and class instances, find all the
namespaces in the WMI store, etc. There is a complete section in this article dedicated to
these classes. The System.Management.Instrumentation namespace provides the classes
and attributes which makes it very easy to register classes in the WMI store, provide
dynamic class instances, and raise WMI events. The next section in this article explains
those types and attributes. The .NET implementation of WMI has the following major
limitations:

• WMI classes defined through managed providers cannot implement methods or


qualifiers. However, it is possible to call methods of classes defined through
unmanaged code.
• Properties defined through managed providers are read-only for consumers.
• WMI classes defined through managed providers are always marked with the
Dynamic qualifier.
Hopefully future versions of the .NET framework will remove those limitations. But the .NET
framework makes it very easy to define WMI classes, raise WMI events and provide
dynamic WMI class instances.

A look at the System.Management.Instrumentation


namespace

The System.Management.Instrumentation namespace provides a number of attributes


which makes it very easy to instrument your application. First you add a reference to the
System.Management assembly to your project. Then you mark your assembly so that it
provides management instrumentation by applying the InstrumentedAttribute on the
assembly level. Add the following line to your Assembly.cs file (and don't forget to import
your namespace with the "using" keyword).
[assembly: Instrumented("root/enterpriseminds")]

Specify the namespace hierarchy your WMI classes and events will appear in. The .NET
framework will create this namespace for you when registering the WMI classes in the WMI
store. Always start with the root namespace and use the forward slash and not the
backward slash as WMI itself does. Next define the WMI classes and WMI events you want
to expose. You can do this through attributes or by inheriting from the Instance or
BaseEvent classes provided by .NET. Here is how you define a WMI class using attributes:

[InstrumentationClass(InstrumentationType.Instance)]
public class InfoMessage
{
public string Message;
public string Guid;
public int Type;
}

First define your .NET class (you can also use a struct) and then apply the attribute
InstrumentationClass specifying the InstrumentationType as Instance, meaning you provide
class instances. You can only use simple data types, or complex data types you also register
in the WMI store. For example, you cannot use an enumeration as data type (because it is
unknown to WMI), and you cannot register an enumeration. But you can create your own
MessageType class which you then also register with WMI through the InstrumentationClass
attribute. Inheriting your class from the Instance class provided by .NET achieves the same
as using the InstrumentationClass attribute.

public class InfoMessage : Instance


{
public string Message;
public string Guid;
public int Type;
}

Every public property and public field becomes a WMI class property. Private properties,
private fields, and all methods are ignored. The class also gets assigned the Dynamic and
Provider qualifiers. The .NET framework uses its own WMI classes for this purpose -
WMINET_InstrumentedAssembly and WMINET_ManagedAssemblyProvider. Whenever your
WMI class gets registered in the WMI store (which happens every time the WMI class to
register changes) it creates a new WMINET_InstrumentedAssembly and
WMINET_ManagedAssemblyProvider class instance and sets the value of the Provider
qualifier of your class to the value of WMINET_ManagedAssemblyProvider.Name. This
information tells the WMI service and .NET framework how to find the dynamic provider,
which consists of your assembly and types representing this WMI class.

You can apply the IgnoreMemberAttribute to any public property or public field you don't
want to be registered as property in the WMI class. To provide an instance of the WMI class
to consumers you create an instance of your .NET class, set its values and then call
Instrumentation.Publish() to publish the class instance. From then on the object is visible to
any WMI consumer.

// create a new message


InfoMessage Message = new InfoMessage();

// set its properties


Message.Message = MessageText;
Message.Guid = Guid.NewGuid().ToString();
Message.Type = (int)Type;

try
{
// publishes the message to the WMI repository
Instrumentation.Publish(Message);
}

// we have not been able to publish the message


catch(ManagementException)
{
}

If you inherited your class from the Instance class instead of using the attribute then you
have a Published property. Setting it to true publishes the class instance. WMI classes
created through managed providers are dynamic, meaning that, when your application
domain gets destroyed and your assembly unloaded, any class instance you published gets
revoked automatically. You can revoke any class instance you published by calling
Instrumentation.Revoke() and passing along the same class instance (or for classes
inherited from the Instance class you set the Published property to false).

WMI classes are your choice if you want to publish information so consumers can query it
and get information about your application or assembly. WMI events are your choice if you
want to proactively notify consumers about something. There is not much difference in
declaring and firing events. You define again your .NET class or struct and apply the
InstrumentationClass, but this time you set the InstrumentationType to Event.

[InstrumentationClass(InstrumentationType.Event)]
public class EventDetails
{
public string Message;
public string Guid;
public int Type;
}
The same limitations apply as to WMI classes. Only simple data types or complex types
which are also registered as WMI classes can be used. You can also inherit the class from
BaseEvent instead of applying the attribute.

public class EventDetails : BaseEvent


{
public string Message;
public string Guid;
public int Type;
}

Events are not published and revoked like class instances. Events are fired at a given time
and any consumer listening to this event type will receive it. But any consumer subscribing
to this event type afterwards will not get the event. It will only get future events fired. Here
is a code snippet which shows how to fire an event:

// create a new event


EventDetails Details = new EventDetails();

// set the event details


Details.Message = Message;
Details.Guid = Guid.NewGuid().ToString();
Details.Type = (int)Type;

try
{
// fire the event so consumers can consume it
Details.Fire();
}

// catch any exception and return false


catch (ManagementException)
{
}

You first create your .NET class instance, set its properties, and then call the Fire method (if
inherited from the BaseEvent class) or call Instrumentation.Fire() passing along the .NET
object (if you used the attribute to declare your WMI event). This is all you need to do to
publish WMI class instances and fire WMI events. Add a .NET installer so that you can
manually or even automatically register the WMI class and event in the WMI store when
first loading the assembly. Here is the code snippet:

[RunInstaller(true)]
public class MyProviderInstaller : DefaultManagementProjectInstaller
{
}

You can manually run InstallUtil against this assembly to perform the registration in the
WMI store. It really can't get easier to instrument your application.

A simple WMI consumer


You can do more then just write your own WMI class instance and event provider. You can
also write your own WMI consumer which queries for available WMI class instances and
subscribes to WMI events. The needed types are residing in the System.Management
namespace. The ManagementClass lets you bind to a WMI class through the class path.
WMI paths consist of the machine to query, the namespace hierarchy, followed by the class
path itself. The syntax is as follows:
\<machinename>\root\<namespacename>:<classpath>

You can use a dot instead of the machine name to point to the local machine. For example,
to connect to the WMI class created in the previous section, use the path
"\.\root\enterpriseminds:InfoMessage". Through the method GetInstances() you get a
collection of all class instances of this class. Class instances are represented by the
ManagementObject type. The ManagementObject provides a property collection to access all
the properties defined by the class. The following code snippet queries for all available class
instances of the InfoMessage class:

ManagementClass WMIClass = null;

try
{
// bind to the WMI class
WMIClass = new ManagementClass(@"\.\root\enterpriseminds\InfoMessage");

// now loop through all the object instances


foreach (ManagementObject Object in WMIClass.GetInstances())
{
// create a new message
InfoMessage Message = new InfoMessage();

// read the properties out of the object instance


Message.Message =
Convert.ToString(Object.Properties["Message"].Value);
Message.Type = Convert.ToInt16(Object.Properties["Type"].Value);
Message.Guid = Convert.ToString(Object.Properties["Guid"].Value);

// add the new message to the list view


ItemCollection.Add(new ListViewItem(new string[] {
Message.Message,
Message.Type.ToString(), Message.Guid }));

// release the underlying COM object


Object.Dispose();
}
}

// any exception happening is shown


catch (Exception e)
{
MessageBox.Show(e.Message);
}

// release the underlying COM object


finally
{
if (WMIClass != null)
WMIClass.Dispose();
}

First we bind to the WMI class, then we loop through the collection of class instances we
obtain by calling GetInstances() on the ManagementClass type and for each class instance
we read from the property collection the three properties Message, Type and Guid. Each
class instance we find gets added to a list view. The .NET WMI types are built on top of the
unmanaged WMI API. Therefore you should call Dispose() on each ManagementObject you
get from GetInstances() as well as on the ManagementClass object itself. That is all you
need to do to get the class instances of any WMI class.

You can perform WQL queries against the WMI store. WQL is built on top of the SQL
language with some variations, the main difference being that you can only query for data
and not perform updates or deletes. A separate section of this article is dedicated to WQL.
To subscribe to WMI events you use the WqlEventQuery type which creates the appropriate
WQL query for you. When you create an instance of WqlEventQuery you pass along the
event class name to query for and an optional condition, like any SQL WHERE condition. The
condition allows you to query for only specific events, for example all EventDetails events
where the Type property is set to one InstrumentationConsumer Consumer = null;
WqlEventQuery EventQuery = null;
ManagementScope Scope = null;

try
{
// create a event query object
EventQuery = new WqlEventQuery("EventDetails");

// define the search scope - which machine and namespace


Scope = new ManagementScope(@"\.\root\enterpriseminds\EventDetails");

// create a watcher object we use to get async notifications


EventWatcher = new ManagementEventWatcher(Scope, EventQuery);

// register the delegate to call when an event arrived


EventWatcher.EventArrived += new
EventArrivedEventHandler(Delegate_EventArrived);

// start listening for events


EventWatcher.Start();
}

// show any exception happening


catch (Exception e)
{
MessageBox.Show(e.Message);
}

This code snippet subscribes to EventDetails events in the "\.root\enterpriseminds"


namespace. To synchronously wait for the next WMI event call WaitForNextEvent() on the
ManagementEventWatcher object. This call waits till the next instance of that event is
available and then returns. The code snippet above performs an asynchronous read by
setting the event handler to be called when an event arrives and then calling Start() on the
ManagementEventWatcher object. This allows your application to get notified about WMI
events while performing other tasks. The next code snippet shows an example of the
EventArrived event handler (of the type EventArrivedEventHandler):

public void Delegate_EventArrived(object sender, EventArrivedEventArgs e)


{
// create a new event info
EventDetails Details = new EventDetails();

// get the event details


Details.Message =
Convert.ToString(e.NewEvent.Properties["Message"].Value);
Details.Type = Convert.ToInt16(e.NewEvent.Properties["Type"].Value);
Details.Guid = Convert.ToString(e.NewEvent.Properties["Guid"].Value);

// now add the event to the list view


EventCollection.Add(new ListViewItem(new string[] { Details.Message,
Details.Type.ToString(), Details.Guid }));
}

The EventArrivedEventArgs.NewEvent contains a reference to the received WMI event and is


of the type ManagementBaseObject. It provides access to the property collection of the WMI
event which we use to read the event details and then we add the event to a list view.
Finally if you do not want to receive any further events you call Stop() on the
ManagementEventWatcher object and then Dispose() to free the underlying COM object.
Here is a code snippet:

// stop the event listening


EventWatcher.Stop();

// and dispose the underlying COM object


EventWatcher.Dispose();

It is also very simple to subscribe and asynchronously receive WMI events. It is also very
powerful to perform that against any machine on your network which has the WMI
infrastructure installed, which all new Windows releases do. A good example would be a
server application which you deploy onto multiple servers. How do you monitor it and make
sure you get notified as soon as a critical error happens? With WMI you can achieve that
fairly easily. When a critical error happens, you raise a WMI event. You then write a small
application which subscribes to this WMI event on all the machines this server application is
running on. And as soon as one raises an event, you can display it on a central console. This
simple management tool could be very powerful and helpful for monitoring your server
application. Microsoft provides such a management tool, just much more sophisticated
Operations Manager 2005.

The attached sample application


The attached Windows form sample application provides an instrumentation provider as well
as an instrumentation consumer. The provider application demonstrates how to create and
publish class instances, how to revoke published class instances and how to raise WMI
events. The consumer application demonstrates how to subscribe and asynchronously
receive WMI events and how to query for instances of a WMI class. The provider application
raises a WMI event when started as well as when closed. For more details see the included
readme.htm file. Please note that Windows 2000 SP4, Windows XP SP2 or Windows 2003
SP1 (or KB836802 for Windows 2003) are required for subscribing to WMI events. This is
due to a known bug in the WMI API.

A look at Microsoft Operations Manager 2005


There are a number of enterprise monitoring solutions on the market, one of them being
Microsoft Operations Manager 2005. Microsoft IT uses MOM 2005 to manage its 6,000 or
more servers in over 200 countries. This article will briefly explain how MOM 2005 works
and how you can configure it to receive WMI events and raise alerts to IT operators. This is
a very powerful way you can alert IT operators about critical errors happening in your
application.

To install MOM 2005 launch setup and first perform the option "check prerequisite". Select
all the items under "Microsoft Operations Manager 2005 components" and click Check. This
will check that all the pre-requisites like Windows 2000 SP4 or Windows 2003, MDAC 2.8,
SQL Server 2003 SP3a and the .NET framework 1.1 are installed on the machine. After all
the pre-requisites are installed, go back to the main setup screen and select the option
"Install Microsoft Operations Manager 2005". Select the typical installation which will again
perform a pre-requisite check. The check will pass as we already made sure that all pre-
requisites are installed. Next select the database server to use followed by the database size
which needs to be at a minimum 300 MB. If you have multiple management servers
running, then you can group them in one or multiple groups. The group name cannot be
changed after the installation. Next you enter the group name to use, for example
"Development". Next you enter the Windows account to be used by any action performed by
this management server, for example to gather information from providers, install and
uninstall agents, etc. Next you enter the Windows account to be used to access the MOM
database server. Finally it asks whether to enable error reporting and whether to send them
automatically to Microsoft - always a good idea. When the install is completed you find a
new start menu item under "Programs | Microsoft Operations Manager 2005".

MOM 2005 consists of an "Administrator Console" and an "Operator Console". This separates
very well the administrative tasks from the operational tasks. Administrative tasks are
installing agents at new servers to monitor, setting up new event providers like a WMI
event, setting up alert rules like "email or page an operator", etc. Operative tasks are
looking at the health of monitored servers, reacting to alerts, analyzing event and alert
information, etc. So Operators are the IT professionals who use MOM 2005 as a tool to look
after the server and IT infrastructure they are responsible for. First launch the
"Administrator Console" to set up MOM to receive the WMI events we are raising in our
application. This shows the console tree on the left side and the "Information Center" on the
right side. The information center gives you access to documentation, MOM downloads, the
MOM home page, etc.

MOM utilizes so called Management Packs, which are a set of rules, providers, scripts, tasks,
etc. A Management Pack encapsulates all the management aspects to monitor an
application or infrastructure component. You can say it encapsulates all the knowledge to
manage that application or component. The ISV of that application or component should
provide the Management Pack, as the creators also know best how to monitor it and keep it
running reliably. Microsoft internally mandates that all future server products/releases
shipped need to provide a Management Pack. MOM installs out of the box with the
"Microsoft Operations Manager 2005" Management Pack but ships with a number of other
Management Packs which you can import, for example for SQL Server, Active Directory,
Systems Management Server, IIS, DNS, etc. To import a Management Pack, click on the
item "Management Pack" in the console tree and select "Import/Export Management Pack"
from the popup menu. Next select that you want to import a Management Pack followed by
the folder where the Management Pack is located. Your MOM 2005 CD has a folder called
"ManagementPacks". Browse to it and on the next screen you find all the Management
Packs available in that location. Select one or more Management Packs to import, for
example "Microsoft SQL Server 2000" and "Microsoft Windows IIS". During the import it
shows you a detailed progress screen. When done you will see new items appearing under
the "Management Packs" item in the console tree. For example under "Rule and Groups"
you see "Microsoft Windows Internet Information Services" and "Microsoft SQL Server".
Underneath you find detailed event and alert rules which are recommended by those
Microsoft product groups.

Creating your own Management Pack


As an ISV, it is very simple and also recommended to create your own Management Pack
and ship that with your product. That makes it much simpler for IT groups to monitor and
maintain your application. First create your own "Rule Group" where you define all the event
and alert rules around your product. Under the item "Management Packs" you find the item
"Rules and Groups". Right click on it, select "Create Rule Group" from the popup menu and
enter the name and description describing your product (for example "Enterprise-Minds
Instrumentation Sample"). On the following screen you enter the "Company Knowledge
Base", which is really a description of the Management Pack and the product it monitors.
Click on the "Edit" button to enter the text. When you are finished it asks whether to deploy
the new "Rule Group" to a group of computers. Through this option you select the group of
computers the rules in this "Rule Group" will apply to. Select "yes" and click the "Add"
button to add a computer group. It shows you the list of defined computer groups. Double
click on one if you want to see details about the computer group. The "Formula" tab shows
the formula used to determine which computers belong to the group. If you run the sample
application on the machine you installed MOM 2005 on, select the computer group
"Microsoft Operations Manager 2005 Servers". After you selected one or more computer
groups, click Ok to save the new "Rule Group".

Expand the newly created "Rule Group" with the plus sign in front of it. Next create a new
event rule (events meaning MOM events collected). Right click on the item "Event Rule",
select "Create Event Rule" from the popup menu and from the list select "Alert on or
Respond to Event (Event)". First you select an existing event provider or create a new one.
Create a new event provider by clicking on the button "New". The provider type we use is
WMI, so select "WMI Events" from the list. Next enter the name of the new provider, for
example "Enterprise-Minds WMI Event". Then you enter the namespace the WMI class is
residing in which is, in our case, "root\enterpriseminds". Next you enter the WQL query this
provider executes against WMI, which in this case is "SELECT * FROM EventDetails". To
query only for certain properties, list the properties instead of the star, for example "SELECT
Message, Type FROM EventDetails". This query returns any WMI event raised by the sample
application. Another way to only return certain properties is to list the properties in the
"Property list" field, for example "Message, Type". Click "finish" to create this new provider,
which brings you back to the "Event Rule" creation process and selects the new provider in
the drop down list.

On the next screen you could apply a filter if you don't want to receive all events, for
example only receive events where the Type property has a value of one. Later in the article
it is explained how to filter events based on the WMI event values. Next you could define
that this rule only runs on certain days and times, the default being "process at any time".
Next you can generate an alert by selecting the "Generate Alert" checkbox. Select a severity
of the alert which is by default "Critical Error". Later in the article it is explained how you
can generate different alerts based on the values provided by the WMI event. Next you
select if you want to suppress duplicate alerts, which is the default selection, and which
criteria are used to determine whether it is a duplicate alert. The default criterion used is if
the alert comes from the same computer and domain. This reduces the amount of alerts an
Operator has to deal with, as it is very likely that the same alert will be raised many times
till the issue is resolved. It is enough that the Operator sees one alert which keeps the noise
level down. Next you define response actions which should be executed when the event
happens, for example execute this script which may restart an application. This allows
automating some of the actions to be taken when this event happens. Next you enter a
knowledgebase which allows you to describe the issue in detail and standard
troubleshooting steps to be taken. This helps Operators to understand how to resolve an
issue. Finally you give the event rule a name, for example "Instrumentation Sample Rule".

This is all you need to do to capture WMI events and raise alerts to Operators. In order for
all the changes to take effect you need to right click on the item "Management Packs" and
select "Commit Configuration Change" from the popup menu. By default, changes are only
committed and take effect after five minutes. With this you can commit the changes right
away. To change this default setting, select the item "Administrator | Global Settings".
Then, in the list on the right side, select "Management Servers", double click the item you
want to change and, on the "Rule Change Polling" tab of the dialog that comes up, change
the time till changes are committed.

The IT Operator view in MOM 2005

IT Operators do not administrate MOM but rather have an operative view over all the
servers and components they are responsible for. The "Operator Console" can be launched
through the start menu "Programs | Microsoft Operations Manager 2005". The navigation
pane on the left (same look as in Outlook 2003) lets you navigate to different views, the
most important being the event, alert, state and performance views. The "event" view
shows you all the events available. The "alert" view shows all the alerts which have been
raised to the Operator. The "state" view provides a very quick and good overview of the
health state of each computer. It shows all the main components monitored and the state of
each. For example it can show that the overall health of the machine is "critical error". But
the IIS and MOM Agent are healthy and the SQL component is the one which raised the
"critical error". This helps a lot to understand very quickly which components on which
servers need attention. Double clicking on a server in the state view shows all the alerts for
this server. Events can then be used to get a much better understanding of what happened
before, during, and after the time of error. The performance view shows performance for all
the performance rules set up.

Next launch the "InstrumentationProviderForm" sample application attached to this article.


Launching it will raise an EventDetails WMI event which MOM 2005 is now listening for. In
the same application you can enter the event text, select the event type and then click the
"Fire event" button to raise additional WMI events. Go back to the "Operator Console" and
to the alerts view. You will see now an alert generated because of the WMI event fired by
the sample application. Click on the alert and you will see its details in the lower "Alert
Details" pane. In the alert details you see all the WMI event properties MOM received. You
see first the system properties like __PATH (the WMI event path), __SUPERCLASS (the
class this WMI event inherited from), etc. You then see also all the WMI event properties
itself. Please take special note of the order they appear in. Later in the article when we set
event filters and alert severity, you can select the properties by number. For example, the
__PATH property is the fifth one so you can chose it by the name Parameter 5, the Message
property is Parameter 10 and the Type property is Parameter 11. Also take special note of
the value of the Type property. The property is of type integer in the .NET code but it is
shown here as "0 (0x0)", "1 (0x1)", etc. So MOM reads the numeric value and converts it to
a string which has in parenthesis the hexadecimal string representation of the value.

If you select the Event tab in the "Alert Details" pane then you see all the events which
raised this alert. In the alert details there is a wealth of information available, such as when
the alert was first and last raised. When the issue has been resolved, the Operator right
clicks on the alert, selects "Set Alert Resolution State | Resolved" and then enters a
description how it was resolved for future reference. Through that menu Operators can also
set other alert statuses, such as that it has been assigned to a vendor or subject matter
expert, or it might require a scheduled maintenance. When all alerts have been resolved
then the health state is set back to "Success".

Filtering MOM events and setting alert severity levels

Let's go back into the Administrator Console and filter the MOM events, meaning we want to
see only MOM events when the WMI event type is set to "Application Start" (value 0) or
"Application Stop" (value 1). Open up the properties of the "Instrumentation Sample Rule"
rule, go to the tab "Criteria" and select the "Advanced" button. Remember that the Type
property is the Parameter 11. At the bottom select Parameter 11, select the Condition
"equal", and enter as value "0 (0x0)" (remember it is converted to a string including the
hexadecimal string representation in parenthesis). This criterion would return only events of
the type "Application Start". Because we want to have all WMI events except the "User
Initiated", we select the Condition "not equals" and the Value "2 (0x2)". Click on the button
"Add To List" to add it to the criteria list. You can add multiple criteria, but each field can
only be used for one criterion. If you want to edit a criterion then select it in the list on top
and click the button Remove. This removes the criterion but shows it in the
Field/Condition/Value controls at the bottom so you can change it and then add it again.

Save the event rule and don't forget to commit the configuration changes (right click on
Management Packs and select "Commit Configuration Change" from the popup menu). Go
back to the sample application and manually raise three events, setting the Type for each to
"Application Start", "Application Stop" and "User Initiated". Go back to the Operator console
and refresh the Events view (key F5) and you see only two events. Select each and check
the value of the Type property and you will see that the one with the value "2 (0x2)" (which
is "User Initiated") is not present, because it has been filtered. Switch to the alert view and
you will see only one alert, because we suppress duplicates. Select the alert and select the
Events tab in the "Alert Details" pane and you see the two events which raised the alert. Set
the state of the alert to resolved so we have no alerts for our next scenario.

Now this time we want to get all events but for different values in the Type property we
want to raise alerts with different severity. Bring up again the properties of the
"Instrumentation Sample Rule" rule. First go to the Criteria tab and remove the filter (click
on the Advanced button, select the criterion in the list and click the Remove button). Next
go to the Alert tab and select the check box "Enable state alert properties". This allows us to
create a complex rule which defines the severity on property values. Click on the Edit button
beside the "Alert severity". Click Edit to edit the default condition added by MOM. The new
dialog allows you to create a complex condition, and the severity level if that condition is
met. Select Parameter 11 through the Parameter button on the left side. You see that it
adds "AttributeValue(Parameter 11)" to the condition text box. Edit it so it says
"AttributeValue(Parameter 11) = "0 (0x0)"" and set the alert severity to "Information"
through the drop down list at the bottom. This condition says if the event Type property is
set to "Application Start" then raise an information alert. Go back to the condition dialog
and click on the Add button to add another condition. Select again Parameter 11, set the
condition to "AttributeValue(Parameter 11) = "1 (0x1)"" and set the severity level to
"Critical Error". This condition says when the event Type property is "Application Stop" then
raise a "critical error" alert. Repeat the same steps to add a condition
"AttributeValue(Parameter 11) = "2 (0x2)"" where the severity is set to warning. This
condition says when the event Type property is "User Initiated" then raise a warning alert.
Close the condition dialog, which brings you back to the alert tab on the event rule. We are
raising now three different alerts, which means you also need to change the criteria used by
MOM to suppress duplicate alerts. Set the "Server role" to "MOM Agent", the "Component"
to "WMI" and for the Instance you select (through the arrow on the right) "Source
Computer" and then "Parameter 11". This sets the Instance value to "$Source
Computer$$Parameter 11$". So only duplicate alerts coming from the same machine with
the same Parameter 11 value (which is the event Type property) are suppressed.

Commit the configuration changes and go back to the sample application. Manually raise
three events again, setting the Type for each to "Application Start", "Application Stop" and
"User Initiated". Go back to the Operator Console and you will see again three events, but
you also see three different alerts. One with the severity "information", one with the
severity "warning" and one with the severity "critical error". If you raise multiple events
through the sample application you will also see that only one alert per severity is raised.

Creating your Management Pack


Now that we have created our provider, rule, and alerts, we want to package that up into a
distributable Management Pack. This allows you to distribute this Management Pack to your
customers. Right click on the item "Management Packs" and choose "Import/Export
Management Pack" from the popup menu. Next select the option "Export Management
Packs" which brings up the list of existing Rule Groups. Select the Rule Group
"Instrumentation Sample Rule", meaning we want to export all event rules, alert rules and
performance rules of this Rule Group. Next it allows you to select Views and Tasks to
export. We have not created any views or tasks so we do not select any. Finally it asks for
the name and location of the Management Pack to create, for example "c:\Enterprise-Minds
Management Pack". The exported file ends with the extension "akm" and can be imported
like any other Management Pack (see earlier in the article). The sample application attached
includes the sample Management Pack we created in this article.

Note that you can also delete Rule Groups but only if there are no alerts present for the
rules defined in that rule group. If there are alerts present it will show a message stating
you can't delete the rule group because alerts are associated with it. Unfortunately there is
no simple way to resolve this. MOM 2005 stores all information in the SQL Server database
called OnePoint. Delete all the alerts from the following tables - AlertHistory, AlertEvent,
AlertEventSuppression and Alert. This is very useful when you want to remove all rules,
providers and alerts created and then test if the Management Pack you created includes all
information and functions properly. This approach is only recommended for development
environments. For production environments refer to the section "database grooming" in the
MOM 2005 documentation.

Download Source
Summary
WMI and Microsoft Operations Manager 2005 provide a compelling and simple way to make
available sophisticated management instrumentation for your enterprise applications. The
.NET framework makes it easy to create your own WMI classes and events, and registers
them for you in the WMI store. Exposing WMI class instances and raising WMI events is
very easy. The declarative style using attributes makes it especially intuitive. Also, querying
the WMI store for class instances and subscribing to receive WMI events asynchronously is
fairly simple. This allows you to create your own simple management tools. MOM 2005 is a
very compelling management tool for your IT infrastructure and applications. It provides
sophisticated information gathering and analyzing capabilities which gather a wealth of
information but only alert operators to relevant information. MOM 2005 excels with its new
Operator Console specifically targeted at the IT operator, and its new "health state" view
which provides a very good overview of machine and component health statuses. MOM
provides many more features which are beyond the scope of this article.

The second part of this article will dive deeper into the WMI store, classes and class
instances. WMI can provide a wealth of information about a machine. The sample
application for the second article will provide a "WMI System Browser" which enables you to
find Windows and hardware serial numbers, a list of installed OS hotfixes, a list of
processors with clock speed and current processor status information, and much more. The
article will cover how to programmatically create and edit class and class instance
information. If you have comments to this article, please contact me @
klaus_salchner@hotmail.com . I want to hear if you learned something new. Contact me if
you have questions about this topic or article.

About the author


Klaus Salchner has worked for 14 years in the industry, nine years in Europe and another
five years in North America. As a Senior Enterprise Architect with solid experience in
enterprise software development, Klaus spends considerable time on performance,
scalability, availability, maintainability, globalization/localization and security. The projects
he has been involved in are used by more than a million users in 50 countries on three
continents.

Klaus calls Vancouver, British Columbia his home at the moment. His next big goal is doing
the New York marathon in 2005. Klaus is interested in guest speaking opportunities or as an
author for .NET magazines or Web sites. He can be contacted at
klaus_salchner@hotmail.com or http://www.enterprise-minds.com .

Enterprise application architecture and design consulting services are available. If you want
to hear more about it contact me! Involve me in your projects and I will make a difference
for you. Contact me if you have an idea for an article or research project. Also conact me if
you want to co-author an article or join future research projects!
An in-depth look at WMI and instrumentation, Part II
By Klaus Salchner

Introduction
The first part of this article explained how to instrument your application. We looked at a
simple WMI provider to demonstrate how to define WMI classes, how the .NET framework
registers these classes in the WMI store, how to publish class instances and how to raise
WMI events. On the other hand we looked at a simple WMI consumer to demonstrate how
to query for WMI class instances and how to subscribe to and receive asynchronously WMI
events. Finally we looked at Microsoft Operations Manager 2005, how to set it up to monitor
WMI events raised by instrumentation applications and how to create Management Packs to
distribute to customers. This gives a comprehensive view about how to instrument
applications and how to tie this in with management applications like MOM 2005.

This second part looks in more detail at how to query the WMI store, how to work with WMI
classes and class instances, and then demonstrates the wealth of information available
through the Win32 and IIS WMI providers. This article has two sample applications
attached. The "WMI System Browser" allows you to browse a wealth of information about
your machine. The "WMI Power Browser" allows you to browse the WMI schema and look in
detail at classes and class instances. All .NET types for working with WMI reside in the
System.Management DLL, so you need to add the System.Management namespace to your
code.

Working with WMI namespaces

WMI supports namespaces, allowing users to logically group WMI classes together. Each
WMI provider normally registers its own WMI namespace and then all its classes within that
namespace. For example, all Win32 WMI classes can be found in the namespace
"root\cimv2", all IIS WMI classes can be found at "root\microsoftiisv2", and all LDAP WMI
classes can be found at "root\directory\ldap". The root namespace is called "Root" and
namespaces can have child namespaces and WMI classes. Each namespace contains a class
called __namespace and its class instance list gives you a list of all child namespaces. Here
is a code snippet for that:
// the root namespace we are connecting to
ManagementScope Scope = new ManagementScope(@"\.\Root");

// the __namespace class to connect to - which provides a list of


// all child namespaces in the namespace we are connecting to
ManagementPath ClassPath = new ManagementPath("__NAMESPACE");

// connect to the namespace and class


ManagementClass WMIParentObject = new ManagementClass(Scope, ClassPath,
null);

try
{
// now loop through all the object instances we find for that namespace
class
foreach (ManagementObject WMIChild in WMIParentObject.GetInstances())
{
// a child-namespace found
string ChildNamespace =
Convert.ToString(WMIChild.Properties["Name"].Value);

// add the namespace name to the tree view


TreeNodeCol.Add(WMIChild.Path.Path, ChildNamespace.ToLower());

// release the underlying COM object


WMIChild.Dispose();
}
}

// show any exception happening


catch (Exception e)
{
MessageBox.Show(e.Message);
}

// release the underlying COM object


finally
{
WMIParentObject.Dispose();
}

It first creates a ManagementScope object and sets it to the root namespace on the local
machine. This defines where (which machine and namespace) the class we are binding to is
residing. Next we create a ManagementPath setting it to the WMI class we are binding to
(the __namespace class). Finally we create a ManagementClass object using the scope and
path object we created. The same could be achieved by only creating a ManagementClass
object and passing along the path "\.\root:__namespace". When you have bound to a WMI
class, you can call GetInstances() to get a list of all class instances for this class. In the case
of the __namespace class this is the list of child namespaces. The path and the name of
each namespace is then used to add it to a tree view. The ManagementClass and
ManagementObject classes use underlying unmanaged COM objects, so call Dispose to
release them.

The WMI infrastructure allows you to apply security to each namespace. Open up the
"Computer Management" console in Windows (right click on "My Computer" and choose
Manage from the popup menu) and navigate to the item "Service and Applications" and
then "WMI Control". Open up the properties of the "WMI Control" item and navigate to the
"Security" tab. It allows you to navigate the namespace hierarchy (shown in a tree view).
Select the one you want to set the security for and click on the "Security" button. This
brings up the standard Windows ACL dialog and allows you to set the rights for each
Windows user or Windows group. The available rights are:

• Execute Methods Allows user to execute methods defined on the WMI classes.
• Full Write
• Edit Security information

This allows you to set granular access rights for the classes and class instances in this
namespace. The list of security rights shown is on Windows 2003. On Windows XP, "Enable
Account" is named "Enable" and "Full Write" is named "Full Control". All other security rights
are named the same.
Working with WMI classes
The class ManagementClass allows you to bind to and work with WMI classes. The path of a
WMI class consists of the machine, followed by the namespace hierarchy ending with a
colon and the class name itself, for example "\.\Root\cimv2:Win32_Volume". The
ManagementClass provides access to the following information:

• SystemProperties an array of strings.


• __Dynasty example __SystemClass. This value is the same as __Derivation if the
class inherited from has no parent class, such as the class __Provider (inherits from
__SystemClass which has no parent class).
• __Path
• __Relpath which excludes the machine and namespace (this is everything after the
colon of the full path). In our example this is __Win32Provider.
• __Namespace
• __Server
• __Property_Count

This collection is of the type PropertyDataCollection which is a collection of PropertyData


types. The type PropertyData exposes Name and Value properties. The property IsArray can
be used to determine whether Value is an array of values or a single value.

• Properties writing property values on a class instance. This is also of the type
PropertyDataCollection, which is again a collection of PropertyData types.
• Qualifiers href="http://msdn.microsoft.com/library/en-
us/wmisdk/wmi/wmi_qualifiers.asp"> here. Some examples are:

• Abstract
• Dynamic .NET instrumentation (see part I of this article) are marked dynamic.
• Provider
• Singleton

This is a collection of the type QualifierDataCollection which is a collection of


QualifierData types which exposes Name and Value properties to read the name and
value of the qualifier.

• Methods A collection of methods defined by this WMI class which can be invoked by
class instances. This collection is of the type MethodDataCollection which is a
collection of MethodData types. The MethodData type exposes a Name property for
the method name and InParameters and OutParameters properties which provide
access to all in and out parameters of the method. InParameters and OutParameters
are of the type ManagementBaseObject. They have a "Properties" property, of type
PropertyDataCollection which is a collection of the type PropertyData, providing
access to each individual in or out parameter. You can read the name, the value,
check if it is an array of values or a single value, etc. The return value of the method
is an out parameter with the name ReturnValue.

These four collections provide you with a wealth of information about the WMI class. They
can be used to read information about a WMI class and also to edit a WMI class (shown by
the attached "WMI Power Browser" application). Here is a code snippet illustrating how to
read class information.
ManagementClass WMIClass = null;

try
{
WMIClass = new ManagementClass(@"\.\root\cimv2:__Win32Provider");

// add all the properties to the list


foreach (PropertyData Property in WMIClass.Properties)
ListCollection.Add(new ListViewItem(new string[] { "Property",
Property.Name, GetPropertyValue(Property) }));

// add all the system properties to the list


foreach (PropertyData Property in WMIClass.SystemProperties)
ListCollection.Add(new ListViewItem(new string[] {
"SystemProperty",
Property.Name, GetPropertyValue(Property) }));

// add all the qualifiers to the list


foreach (QualifierData Qualifier in WMIClass.Qualifiers)
ListCollection.Add(new ListViewItem(new string[] { "Qualifier",
Qualifier.Name,
Convert.ToString(Qualifier.Value) }));

// add all the methods to the list


foreach (MethodData Method in WMIClass.Methods)
ListCollection.Add(new ListViewItem(new string[] { "Method",
Method.Name, String.Empty }));
}

// show any exception happening


catch (Exception e)
{
MessageBox.Show(e.Message);
}

// release the underlying COM object


finally
{
if (WMIClass != null)
WMIClass.Dispose();
}

This code snippet binds to the __Win32Provider class in the root\cimv2 namespace and then
reads all its properties, system properties, qualifiers and methods and adds for each the
name and value to a list view (note that methods have no values). At the end it calls
Dispose to release the underlying COM object. The value of properties or system properties
can be arrays so it calls GetPropertyValue() which does the following:

public string GetPropertyValue(PropertyData Property)


{
// a single value property so we return its value as string value
if (!Property.IsArray)
return Convert.ToString(Property.Value);

// return a comma separated list of array values


else
{
string PropertyValue = String.Empty;

// loop through all items in the array; only if we have items (!=
null)
if (Property.Value != null)
{
foreach (object Value in ((Array)Property.Value))
PropertyValue += Convert.ToString(Value) + ", ";
}

// return the comma separated list of values for this array


if (PropertyValue.Length > 0)
return PropertyValue.Substring(0, PropertyValue.Length -
2);
else
return String.Empty;
}
}

It checks through IsArray if this is an array or single value. If a single value it converts the
value to a string and returns it. For an array of values it loops through each item and adds it
to a comma-separated list which is then returned.

Working with WQL queries


You can query WMI using the WQL query language. WQL is based on the standard SQL
syntax with some differences, the biggest one being that it allows only queries and not
updates, inserts or deletes. It allows you to query for classes, class instances, class
associations, inherited classes, etc. Queries are always executed against a namespace. Here
are a few examples:

• SELECT * FROM meta_class


Queries for all classes in the namespace.
• SELECT * FROM meta_class WHERE __CLASS = "Win32_Volume"
Queries for a class with the name Win32_Volume.
• SELECT * FROM meta_class WHERE __this ISA "Win32_Volume"
Queries for a class with the name Win32_Volume and all its child classes. So any
class which directly or indirectly is inherited from this class is returned.
• SELECT * FROM Win32_Volume WHERE __CLASS = "Win32_Volume"
Queries for any class instances of the class Win32_Volume.
• SELECT * FROM Win32_Volume
Queries for any class instances of the class Win32_Volume and any other class
directly or indirectly inherited from it.

To execute a WQL query create first a ManagementScope object which defines against
which namespace you want to perform this query, for example "\.\root\cimv2". Next create
an instance of WqlObjectQuery and pass along the query WQL string. Finally create an
instance of ManagementObjectSearcher and pass along the scope and query objects. Call
ManagementObjectSearcher.Get() which performs the search and returns a collection of
ManagementObject objects. Here is a sample code snippet:
// the namespace we are searching in
ManagementScope Scope = new ManagementScope(@"\.\root\cimv2");

// the query we are performing


WqlObjectQuery Query = new WqlObjectQuery("SELECT * FROM meta_class");

// enumeration options to use for the search; set a time-out value


EnumerationOptions Options = new EnumerationOptions();
Options.Timeout = new TimeSpan(0, 0, 10);

// instantiate the searcher object using the scope and query


ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope,
Query, Options);

try
{
// now get the search results and loop through all found object
instances
foreach (ManagementObject Object in Searcher.Get())
{
// add the object to the list view
Collection.Add(new ListViewItem(new string[] { Object.Path.Path,
Object.Path.RelativePath } ));

// dispose the object instance


Object.Dispose();
}
}

// show any exception happening


catch (Exception e)
{
MessageBox.Show(e.Message);
}

// dispose the underlying search COM object


finally
{
Searcher.Dispose();
}

This code snippet sets the search scope to the namespace "root\cimv2" and searches for all
classes in that namespace. It also sets a timeout of 10 seconds for enumerating the result-
set, not for how long the actual search is allowed to take. It adds for each found object the
full and relative path to a list view. Don't forget to call Dispose() on each object in the
enumeration and on the ManagementObjectSearcher object to release the underlying COM
objects.

You can also build associations between different classes using association classes.
Association classes are classes which have references to two other classes and through that
associate these two classes. The diagram below shows the associations between the
Win32_DiskPartition class with the Win32_ComputerSystem, Win32_DiskDrive and
Win32_LogicalDisk class. For each there is an association class:
• Win32_SystemPartitions
computer system. The
GroupComponent property on
this class contains the
reference to the
Win32_ComputerSystem
class while the
PartComponent property
contains the reference to the
Win32_DiskPartition class.
• Win32_DiskDriveToDiskPa
rtition partition. The
Antecedent property on this
class contains the reference
to the Win32_DiskDrive class
while the Dependent property
the reference to the
Win32_DiskPartition class.
• Win32_LogicalDiskToPartit
ion a partition. The
Dependent property on this
class has the reference to the
Win32_LogicalDisk class and
the Antecedent property the
reference to the
Win32_DiskPartition class.

WMI allows you to query for those associated classes and the association classes which
reference the two classes together. This makes it easy to find all associations and
association classes without having to go through the documentation of all classes, which in
the case of "root\cimv2" number in the hundreds. Let's assume your computer has an
instance of the Win32_DiskPartition class with the value "Disk #0, Partition #0" and you
want to find all associated classes and class instances and association classes and class
instances. Here is how it works:

• ASSOCIATORS OF {Win32_DiskPartition.DeviceID="Disk #0, Partition #0"}


Returns all class instances which are associated with this Win32_DiskPartition class
instance. The result may vary based on your hardware and software configuration.
My machine returns an instance of the Win32_ComputerSystem class (value
Enterprise-Minds), an instance of the Win32_LogicalDisk class (value "C:") as well as
an instance of the Win32_DiskDrive class (value "\.\PHYSICALDRIVE0"). Note that
Win32_DiskDrive is your physical disk drive while Win32_LogicalDiskDrive is the
logical disk created through your OS.
• ASSOCIATORS OF {Win32_DiskPartition.DeviceID="Disk #0, Partition #0"} WHERE
ClassDefsOnly
This query returns the WMI class names of all the classes associated with the
Win32_DiskPartition class. My machine returns Win32_ComputerSystem,
Win32_DiskDrive and Win32_LogicalDiskDrive.
• REFERENCES OF {Win32_DiskPartition.DeviceID="Disk #0, Partition #0"}
Returns all the association class instances which have a reference to this
Win32_DiskPartition class instance, meaning one of the properties contains a
reference to this class instance. My machine returns an instance of the
Win32_DiskToDiskPartition class, an instance of the Win32_SystemPartitions class
and an instance of the Win32_LogicalDiskToPartition class.
• REFERENCES OF {Win32_DiskPartition.DeviceID="Disk #0, Partition #0"} WHERE
ClassDefsOnly
This query returns the class names of all the associations classes referencing the
Win32_Partitions class. My machine returns Win32_DiskDriveToDiskPartition,
Win32_LogicalDiskToPartition and Win32_ComputerSystem.

WMI provides a wealth of information, so it is important to have strong query/search


capabilities and to be able to get a good view of the associations between the data. WQL is
build on top of SQL which makes the query language instantly familiar to developers but is
still enhanced to support WMI specific capabilities. You can find out more about WQL from
here as well as here .

Working with WMI class instances


The ManagementObject class can be used to work with WMI class instances. The
ManagementClass type is inherited from the ManagementObject type. This means nearly all
the functionality explained in the section "Working with WMI classes" applies also to WMI
class instances. The two exceptions are that the property values for a class are default
values (if specified) while they return the actual value for a class instance, and there is no
Methods collection, meaning there is no access to the method information. You can obtain
the class information of a class instance through the ClassPath property. This returns a
ManagementPath type which provides access to the class name (ClassName property), the
server queried (Server property), the namespace (property NamespacePath), the full path
(Path property) and the relative path (RelativePath property).

Through ManagementObject.InvokeMethod() you can invoke a method on the class


instance. Managed WMI classes (i.e., those provided by managed code) cannot provide
methods. But many of the unmanaged WMI classes provide methods which you can invoke
to manipulate the class instance. For example the class Win32_Volume has a Chkdsk()
method to perform a check disk, a DefragAnalysis() method to perform defrag analysis, a
Defrag() method to perform a defrag and many more. Query the WMI class to obtain a list
of methods. When you know the method name use the method
ManagementObject.GetMethodParameters() to obtain a ManagementBaseObject with the list
of in parameters for the method. Next set the values for all in parameters and then call
ManagementObject.InvokeMethod() to invoke the method. It returns another
ManagementBaseObject type which contains the values of all the out parameters plus the
method return value. The method return value is stored in the out parameter list as an out
parameter with the name ReturnValue. Here is a code snippet:

ManagementObject WMIObject = null;


string ObjectPath = @"\.\root\cimv2:Win32_Proxy.ServerName=""Enterprise-
Minds""";
string MethodName = "SetProxySetting";

try
{
// bind to the WMI object instance
WMIObject = new ManagementObject(ObjectPath);
// get a WMI object representing all in-parameters for this method
ManagementBaseObject InParams =
WMIObject.GetMethodParameters(MethodName);

// set all the in-param values according to the in-param list view
foreach (ListViewItem Item in InParamItems)
InParams[Item.SubItems[0].Text] = Item.SubItems[1].Text;

// set the method invoke options so that the method has 10 sec to
execute
InvokeMethodOptions Opt = new InvokeMethodOptions();
Opt.Timeout = new TimeSpan(0, 0, 10);

// execute the method on the WMI object and get the out-parameters
ManagementBaseObject OutParams = WMIObject.InvokeMethod(MethodName,
InParams, Opt);

// read all the return values and show them in the out-param list view
foreach (PropertyData Property in OutParams.Properties)
OutParamItems.Add(new ListViewItem(new string[] { Property.Name,
GetPropertyValue(Property) }));

// dispose the COM object of the in param object


if (InParams != null)
InParams.Dispose();

// dispose the COM object of the out param object


if (OutParams != null)
OutParams.Dispose();
}

// show any error message


catch (Exception e)
{
MessageBox.Show(e.Message);
}

// free up the underlying COM object


finally
{
if (WMIObject != null)
WMIObject.Dispose();
}

The code snippet first binds to the Win32_Proxy class instance (note that Enterprise-Minds
is the machine name, which will of course be different for your machine) and then gets the
method in parameters from the GetMethodParameters() method. It then reads all the in
parameter values from the InParamItems list view. Then it invokes the InvokeMethod()
which returns all the out parameters and the method return value. These are then added to
an OutParamItems list view. At the end it calls Dispose on the in parameter and out
parameter types and the class instance itself to release the underlying COM objects. Note
that some out parameter values might be another WMI class instance. The "WMI Power
Browser" sample application attached shows how to check for the type of the return value
and then read the property values of such a returned WMI class instance.
You can also delete class instances, unless they are dynamic. First bind to the class instance
and then call the method ManagementObject.Delete(). Here is a code snippet for that:

ManagementObject WMIObject = null;

try
{
WMIObject = new ManagementObject(ObjectPath);

// delete the object


WMIObject.Delete();
}

// show any exception happening


catch (Exception e)
{
MessageBox.Show(e.Message);
}

// release the underlying COM object


finally
{
if (WMIObject != null)
WMIObject.Dispose();
}

Property values of a class instance can be updated. These changes will not be committed till
you call ManagementObject.Put(). The provider for dynamic class instances needs to
support write access to the property. No managed class instances support write access.
Here is a code snippet showing how to update property values:

ManagementObject WMIObject = null;

try
{
WMIObject = new ManagementObject(ObjectPath);

// loop through all the properties in the list view and get the values
foreach (ListViewItem Item in ItemCollection)
WMIObject.Properties[Item.SubItems[0].Text].Value =
Item.SubItems[1].Text;

// write any changes back to the WMI store


WMIObject.Put();
}

// show any exception happening


catch (Exception e)
{
MessageBox.Show(e.Message);
}

// release the underlying COM object


finally
{
if (WMIObject != null)
WMIObject.Dispose();
}

This sample takes all the new property values from an ItemCollection list view. It first binds
to the class instance and then loops through the list view, gets the latest values and
updates the object property values with it. It then calls ManagementObject.Put() to commit
the changes back to the WMI store (or the provider for dynamic classes). At the end it again
calls Dispose() to free up the underlying COM object.

The "WMI Power Browser" sample application


This sample application demonstrates how to enumerate the list of WMI namespaces and all
classes for each. It also demonstrates how to perform queries, whether querying for all the
classes of a namespace, all class instances of a class, all associated classes and class
instances, all association classes or class instances, etc. It also allows you to enter a WQL
query string and execute the query, showing its result set. This makes it easy to experiment
with WQL and see right away the result set. The sample also demonstrates how to create
new classes, edit or delete new classes, clone class instances and edit or delete class
instances. It also allows you to view all the methods available on a class instance and then
to invoke them. The rich Windows form interface (using tree views, list views, etc.) makes it
very easy to discover all namespaces, classes and class instances. At the same time you can
step through the code and understand in all details how to work with WMI namespaces,
classes and class instances.

The "WMI System Browser" sample application


This sample application shows how you can use WMI to find out a wealth of information
about any machine on your network. The "WMI System Browser" shows only a subset of
information available through WMI. In the list on the left side you can select a category, for
example "processor information", "BIOS information", "IIS web sites", etc. The list in the
middle then shows you all found instances, for example it shows each found processor, each
found IIS web site, etc. Selecting a specific instance shows the details in the list on the right
side, for example the maximum and current clock speed of a processor, the serial number
and release date of the BIOS, etc. Click on the "Show class description" button to launch the
MSDN help page of the underlying WMI class. This helps a lot to understand all the
properties available on a class. If the class exposes methods then you can click on the
"Invoke a method" button. It lists for you on the left side all available methods. Selecting a
method shows you in the list in the middle all in parameters. You can set the values for
each by clicking on it. Click on the "Invoke method" button to invoke the method and show
the out parameters in the list on the right side. Click on the "Show method description" to
launch the MSDN help page for the selected method. This helps to understand the in and
out parameters of each method.

It is very simple to extend the sample application and really understand what information
WMI can provide. This could even be a simple troubleshooting tool, helping the user
understand the hardware and software configuration of a remote machine. Much of the
information shown here can be useful when resolving issues. Here is a list of information
you can view, and which WMI class is used for it:

• IIsWebServiceSetting the IIS itself. This includes ASP settings, logging settings,
authentication settings, etc.
• IIsApplicationPoolSetting application pools (IIS 6.x specific). For each you can
see the user credentials used, application pool recycling policy information, etc.
• IIsWebServerSetting
• IIsWebVirtualDirSetting
• Win32_Battery
• Win32_BIOS
• Win32_ComputerSystem owner, the hardware model and manufacturer, etc.
• Win32_ComputerSystemProduct hardware system including the serial number,
name, vendor, version, etc.
• Win32_DiskPartition Returns the created disk partitions (a disk partition may span
multiple physical disks and contain multiple logical disks). For each you find the size,
block size, number of blocks, etc.
• Win32_Environment each you can see the name, value, if it is a system or user
defined variable, etc.
• Win32_Group - Lists all the Windows groups of your local machine as well as of the
domain, if connected to a domain. For each group you can see the name, domain,
SID, etc.
• Win32_LogicalDisk system and for each the file system, the driver letter, the size
and free space, etc.
• Win32_NetworkAdapterConfiguration configurations (not the physical network
adapters). For each network adapter configuration you see the IP address, subnet
mask, is it DHCP enabled, etc.
• Win32_NTDomain (your local computer is returned as a domain too) and
information like the name, domain controller address, etc.
• Win32_OperatingSystem like build number, serial number, name, OS type, etc.
• Win32_OSRecoveryConfiguration configuration including where to create the
dump file, whether to auto reboot, etc.
• Win32_PageFile including the file path, the file size, etc.
• Win32_PhysicalMemory system and for each the capacity, speed, data width, etc.
• Win32_PnPDevice
• Win32_Printer sizes supported, etc.
• Win32_Process
• Win32_Thread For each thread it shows the total execution time and kernel time in
milliseconds, its priority and the process it belongs to, etc.
• Win32_TimeZone your OS. Returns its name, daylight savings information, etc.
• Win32_UserAccount machine as well as of the domain, if connected to a domain.
For each user you can see the name, domain, SID, etc.
• Win32_Volume capacity, the free size, the file system, etc.

This list already provides a wealth of information about a machine. There are many more
classes available and you can use the "WMI Power Browser" to discover them and each class
instance.

Summary
WMI provides a powerful way to instrument your application and to allow management tools
like Microsoft Operations Manager 2005 to tie into your application and proactively notify IT
operators. But WMI also provides a wealth of information about systems which you can
leverage in your enterprise applications. It is also very easy to collect that information for
remote machines or to invoke actions on class instances remotely. The .NET framework
provides a comprehensive and easy approach to working with WMI. It makes it very easy to
create WMI classes, expose dynamic WMI class instances, raise WMI events as well as
discover and interact with existing WMI classes and class instances.

Hopefully future versions of the .NET framework will remove the existing limitations, the
biggest being that you cannot implement methods, cannot provide write access to
properties and only provide dynamic classes. WMI is still vastly underutilized in today's
enterprise applications. Hopefully these two articles provide a better insight into how to use
WMI and the power of WMI. If you have comments on this article, please contact me @
klaus_salchner@hotmail.com. I want to hear if you learned something new. Contact me if
you have questions about this topic or article.

Download Code.zip

About the author


Klaus Salchner has worked for 14 years in the industry, nine years in Europe and another
five years in North America. As a Senior Enterprise Architect with solid experience in
enterprise software development, Klaus spends considerable time on performance,
scalability, availability, maintainability, globalization/localization and security. The projects
he has been involved in are used by more than a million users in 50 countries on three
continents.

Klaus calls Vancouver, British Columbia his home at the moment. His next big goal is doing
the New York marathon in 2005. Klaus is interested in guest speaking opportunities or as an
author for .NET magazines or Web sites. He can be contacted at
klaus_salchner@hotmail.com or http://www.enterprise-minds.com .

Enterprise application architecture and design consulting services are available. If you want
to hear more about it contact me! Involve me in your projects and I will make a difference
for you. Contact me if you have an idea for an article or research project. Also conact me if
you want to co-author an article or join future research projects!

You might also like