WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

A Quick Introduction to WMI from .NET

by Jim Murphy
04/08/2003

Windows Management Instrumentation (WMI) is Microsoft's implementation of the Web Based Enterprise Management Initiative as defined by the Distributed Management Task Force. Or, if you like, the DMTF WBEM--and let me tell you it's a monster.

There is a lot to the WMI architecture including performance counters, event notifications, configuration management and storage, all built for a distributed environment making WMI the preferred technology for monitoring applications on the Windows platform. Getting at the treasure trove of WMI data and events has always been relatively painless even from scripting environments, but providing that data from your own-instrumented applications has been much more complex. Luckily, the System.Diagnostics, System.Management and System.Management.Instrumentation namespaces contain dozens of classes and interfaces that make consuming and providing WMI data a much easier.

Reading Performance Counters

Management and monitoring are abstract words so what if you just wanted to see the current CPU load of your computer. The System.Diagnostics.PerformanceCounter class makes this straight forward:

PerformanceCounter cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
int value = cpuCounter.NextValue();

That's pretty painless but you're probably wondering where those magic strings came from. Performance counters are organized by category, counter name and instance name as reflected in the signature of the PerformanceCounter constructor. For a list of the counters available, run perfmon (Start-Run-perfmon.exe) and choose "Add Counter". The Add Counter dialog presents the Category/Counter/Instance names for dozens of interesting tidbits of system state. In addition to monitoring hardware and the Win32 subsystem, there are a number of CLR and ASP.NET specific counters that you can use to monitor your managed applications including garbage collection performance, COM Interop details, HTTP processing and even interesting SQLClient events. As we'll see later you can even add your own.

Screen shot.

Visual Studio .NET also includes support for displaying Performance Counters with Server Explorer. Incidentally, the PerformanceCounter class includes overloaded constructors to get at counters on other machines provided your application has the required permissions.

More Advanced Monitoring--WMI Events

Related Reading

Programming .NET Components
By Juval Löwy

Reading system performance counters is a good start on knowing the state of your application platform but that's just the beginning. WMI provides applications a way to subscribe to events, read and write configuration data and enumerate classes and instances of WMI providers.

Applications acting as WMI event consumers subscribe to a plethora of system and custom events using temporary or permanent event subscriptions. Temporary event subscriptions are created by the consuming application and end when the application ends. In this way the subscriptions are only active when the consuming application is running. Compare this to permanent event subscriptions where an application serving as a subscription builder invokes WMI APIs to store subscription information in the machine's CIM repository. When an event occurs the WMI runtime will invoke the script or configured application, starting it if required.

Event subscriptions, made using a WMI Query Language (WQL), allow you to specify exactly the events you are interested in. Its important to realize that events aren't necessarily pre-canned but are parameterized based on the classes and data provided in the WQL query. Navigating the rich and extensible namespace of WMI classes is a little daunting but a little experimenting with the WQL syntax and reviewing the WMI reference documentation will get you started.

Writing Temporary Event Consumers

Writing a temporary event consumer in .NET involves creating a System.Management.WQLEventQuery object, specifying the appropriate WQL query string and associating that query with a System.Management.ManagementEventWatcher. In this example we register a temporary subscription with WMI to fire when our Win32_Process instance's WorkingSetSize exceeds some value.

using System;
using System.Management;
using System.Collections;

class WSMonitor
{
  bool pleaseContinue = true;

  public void doit()
  {
     try
     {
          
        int processId = 
            System.Diagnostics.Process.GetCurrentProcess().Id;
        int workingSet = 30000000; 
        string wqlQuery = String.Format(
           @"SELECT * FROM __InstanceModificationEvent WITHIN 1 
             WHERE TargetInstance ISA 'Win32_Process' AND 
                   TargetInstance.ProcessId = {0} AND 
                   TargetInstance.WorkingSetSize >= {1} AND 
                   PreviousInstance.WorkingSetSize < {2} ", 
           processId, workingSet, workingSet);
          
        WqlEventQuery query = new WqlEventQuery(wqlQuery);
        ManagementEventWatcher watcher = 
           new ManagementEventWatcher(query);
        watcher.EventArrived += 
           new EventArrivedEventHandler(onEvent);
  
        watcher.Start();
        ArrayList array = new ArrayList();
        for (int i = 0; pleaseContinue; ++i)
        {
           array.Add(1);
  
           if (i % 1000 == 0)
              System.Threading.Thread.Sleep(1);
        }
        
        watcher.Stop();
     }
     catch (ManagementException e)
     {
        Console.WriteLine("Management exception: " + e);
     }
  }
  
  public void onEvent(object sender, EventArrivedEventArgs e)
  {
        pleaseContinue = false;
        Console.WriteLine("You're a big boy now!");
  }
}

In the above sample, the WQLEventQuery class is created using a query that fires when the Win32_Process instance's WorkingSetSize property exceeds the value provided. These can look a little strange if you're not familiar with WMI's CIM (Common Information Model), so let’s take a closer look:

SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE
TargetInstance ISA 'Win32_Process' AND 
TargetInstance.ProcessId = 1367 AND
TargetInstance.WorkingSetSize >= 30000000 AND 
PreviousInstance.WorkingSetSize < 30000000

__InstanceModificationEvent is an intrinsic WMI event that fires when any value in the namespace changes. You scope that namespace with the WHERE clause to restrict the event to changes in "Win32_Process" objects that have a ProcessId property equal to the value specified and a WorkingSetSize that just exceeded our setpoint. The WITHIN 1 clause specifies that events should be dispatched within 1 second of the actual event occurring. Increasing this number will increase your notification latency window but will reduce the monitoring overhead associated with polling. TargetInstance and PreviousInstance are fields in the __InstanceModificationEvent class and represent the current and previous value for our Win32_Process class. WorkingSetSize is one of 45 properties on the CIM's Win32_Process class and with literally hundreds of built-in and custom classes there are plenty of events you can monitor. The Win32_Process is a WMI class not to be confused with a managed type written in .NET. WMI classes are types defined using an abstract language called MOF (Managed Object Format) that predates the CLR.

Pages: 1, 2

Next Pagearrow