Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CIMTool for Windows Management Instrumentation - Part 1

0.00/5 (No votes)
22 Feb 2013 1  
Use WMI to retrieve information about your system and genrate classes for easy WMI development.

Harlinn.CIMTool-WPF-Preview-2013-02-21-02.zip contains all you need to run the tool in the 'Harlinn.CIMTool.Wpf\bin\Release' folder. You do not need to download the other archives unless you are interested in the older Windows Forms version.

The next CIMTool article can be found here: CIMTool for Windows Management Instrumentation - Part 2[^]

Part 3 is available here: CIMTool for Windows Management Instrumentation - Part 3[^]

CIMTool WPF edition Preview

Harlinn.CIMTool-WPF-Preview-2013-02-21-02.zip contains a preview of a Windows Presentation Foundation based edition of CIMTool. This edition only relies on .Net 4.0 and a couple of freely available components. This archive contains all you need to run the tool in the 'Harlinn.CIMTool.Wpf\bin\Release' folder.

The external components can be found here:

The WPF edition can be used to browse the WMI namespaces, classes, properties and qualifiers – so it’s useful for browsing the available definitions provided by WMI.

To query the instances of a WMI class, select the class in the treeview, and then right click on the selected item. You can then select Query from the popup menu.

I'm still working on the code generation ...

public class IIsApplicationPool : IIsObject
{

    public IIsApplicationPoolProcessorSettings Cpu
    {
        get
        {
            System.Management.ManagementObject managementObject = GetObject("Cpu");
            IIsApplicationPoolProcessorSettings element = 
                        (IIsApplicationPoolProcessorSettings)
                        IIsWebAdministrationClassFactory.CreateObject(managementObject, 
                                              false);
            return element;
        }
        set
        {
            Write("Cpu", value.ManagementObject);
        }
    }

    public IIsApplicationPoolFailureSettings Failure
    {
        get
        {
            System.Management.ManagementObject managementObject = GetObject("Failure");
            IIsApplicationPoolFailureSettings element = (IIsApplicationPoolFailureSettings)
                        IIsWebAdministrationClassFactory.CreateObject(managementObject, 
                                              false);
            return element;
        }
        set
        {
            Write("Failure", value.ManagementObject);
        }
    }
 
}

The code generation is quite different from what you get with Microsofts mgmtclassgen, and one of the nicer features is that the tool generates code that reflects the object oriented nature of WMI.

To generate code you need to select and right click a namespace in the Classes pane, and then select the Generate Code item.

To use the generated code you need to create a new c# class library and add a reference to the Harlinn.CIMTool.Mgmt.dll assembly. The code generator creates classes for all the WMI classes in a WMI namespace.

Introduction

CIMTool allows you to explore the information provided through the Windows Management Instrumentation API.

You can also use CIMTool to generate c# code for the WMI classes.

If you just want to play around with the tool, unpack the contents of Harlinn.CIMTool.Win-Binaries-Part1.zip, Harlinn.CIMTool.Win-Binaries-Part2.zip, Harlinn.CIMTool.Win-Binaries-Part3.zip and Harlinn.CIMTool.Win-Binaries-Part4.zip into a single directory. The executable is named Harlinn.CIMTool.Win.exe.

It’s something I built because I needed to explore WMI, as some queries did not return the expected information, and I found the WMI Tools a bit cumbersome to use.

CIMTool was built using Windows Forms components from DevExpress, and if you don't have a subscription you can download a 30 day free DevExpress Universal Trial [^] from DevExpress.

Windows Management Instrumentation

WMI provides an interface which allows local and remote applications to obtain management information from a computer system, a network, or an enterprise.

WMI exposes information provided by Managed objects and WMI providers, and a WMI provider is a COM object that monitors one or more managed objects for WMI. A managed object is a physical or logical component, such as a network adapter, database system, operating system or process.

A WMI provider supplies WMI with information from managed objects and passes messages from WMI to the managed objects. A WMI provider consists of a DLL file and a Managed Object Format (MOF) file that defines the classes that the provider exposes information about and/or performs operations on.

The WMI infrastructure is an integral part of the Windows operating system, consisting of two components: the WMI service, including the CIM Object Manager, and the WMI repository.

The WMI repository is organized into a set of namespaces. Initially the WMI service creates namespaces such as root\default, root\cimv2, and root\subscription and installs a default set of class definitions, including the Win32 Classes and the WMI System Classes.

The Common Information Model (CIM) provides a consistent definition and structure of data, using an object oriented technique. The CIM includes expressions for common elements that must be presented to management applications like classes, properties, methods and associations.

CIMTool

CIMTool allows you to take a close look at the WMI managed class structure.

The Classes pane allows you to browse through the namespaces and the classes exposed through WMI. This functionality is implemented through a set of classes representing the various kinds of nodes displayed in the tree.

From a professional standpoint there is something really fascinating about developing software that exposes architectural meta data about meta data.

The abstract NodeBase class implements the DevExpress.XtraTreeList.TreeList.IVirtualTreeListData interface

public void VirtualTreeGetCellValue(DevExpress.XtraTreeList.VirtualTreeGetCellValueInfo info)
{
    if (info.Column.FieldName == "Name")
    {
        info.CellData = GetNodeName();
    }
}

public void VirtualTreeGetChildNodes(DevExpress.XtraTreeList.VirtualTreeGetChildNodesInfo info)
{
    System.Collections.IList theChildren = GetNodeChildren();
    if (theChildren != null)
    {
        info.Children = theChildren;
    }
}

public void VirtualTreeSetCellValue(DevExpress.XtraTreeList.VirtualTreeSetCellValueInfo info)
{
    info.Cancel = true;
}

This is the only code in the nodes class hierarchy that actually has anything to do with the control used to display the WMI namespaces and classes.

NodeBase sets up an infrastructure that allows us to manage the object graph used to navigate the information model exposed by WMI.

protected virtual NodeBase GetNodeParent()
{
    return null;
}

protected abstract string GetNodeName();

protected abstract System.Collections.IList GetNodeChildren();

GetNodeRootNamespace allows us to navigate upwards through the hierarchy to the NodeRootNamespace object representing the "\\.\ROOT" namespace for the WMI repository.

internal virtual RootNamespace GetNodeRootNamespace()
{
    NodeBase theParent = GetNodeParent();
    if (theParent != null)
    {
        return theParent.GetNodeRootNamespace();
    }
    return null;
}
By overriding GetNodeRootNamespace() in NodeRootNamespace
internal override RootNamespace GetNodeRootNamespace()
{
    return this;
}

we effectively return the desred object.

NamedNodeBase introduces a Name property and overrides the GetNodeName() method:

public abstract class NamedNodeBase : NodeBase
{
    string name;
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            if (name == value)
                return;
            name = value;
        }
    }

    protected override string GetNodeName()
    {
        return Name;
    }
}

NamespaceNode

Each CMI namespace is represented by a NamespaceNode

A NamespaceNode represents a single WMI namespace, providing access to the classes and namespaces contained within the namespace.

public class NamespaceNode : NamedNodeBase
{
    List<NamedNodeBase> children;

    NamespacesNode parent;
    ManagementScope managementScope;

In .Net System.Management.ManagementScope represents a WMI namespace.

    internal virtual string GetManagementScopePath()
    {
        if (Parent != null)
        {
            return string.Format("{0}\\{1}",Parent.GetManagementScopePath(),Name);
        }
        return @"\\.\ROOT";
    }

    private void Connect()
    {
        ConnectionOptions connectionOptions = new ConnectionOptions();
        connectionOptions.EnablePrivileges = true;
        string managementScopePath = GetManagementScopePath();
        managementScope = new ManagementScope(managementScopePath, 
                                                   connectionOptions);
        managementScope.Connect();
    }

The GetManagementScopePath() returns a string containing the path to the namespace, and we connect the ManagementScope when it is initially accessed through the ManagementScope property.

    public ManagementScope ManagementScope
    {
        get
        {
            if (managementScope == null)
            {
                Connect();
            }
            return managementScope;
        }
    }

All namespaces, except the root, resides within another namespace, and the Parent property provides access to the NamespacesNode representing the collection of sibling namespaces.

    public NamespacesNode Parent
    {
        get
        {
            return parent;
        }
        set
        {
            if (parent == value)
                return;
            parent = value;
        }
    }

Now that we have an object that actually has a parent we override the GetNodeParent() method, returning a reference to the parent node.

    protected override NodeBase GetNodeParent()
    {
        return Parent;
    }

A NamespaceNode has to child nodes: one NamespacesNode and one ClassesNode.

    protected override System.Collections.IList GetNodeChildren()
    {
        if (children == null)
        {
            children = new List<NamedNodeBase>();
            children.Add(new NamespacesNode(this));
            children.Add(new ClassesNode(this));
        }
        return children;
    }
}

ClassesNode

ClassesNode is a container for all the classes contained within a namespace.

public List<ClassNode> Items
{
    get
    {
        if (children == null)
        {
            children = new List<ClassNode>();
            ManagementObjectSearcher searcher = new ManagementObjectSearcher
                   (ManagementScope, new WqlObjectQuery("select * from meta_class"), null);
            using (searcher)
            {
                foreach (ManagementClass managementClass in searcher.Get())
                {
                    string className = managementClass["__CLASS"].ToString();
                    if (className.StartsWith("__") == false)
                    {
                        ClassNode classNode = new ClassNode(this, className, managementClass);
                        children.Add(classNode);
                    }
                }
            }

            foreach (ClassNode child in children)
            {
                child.ProcessInheritance();
            }
        }
        return children;
    }
}

We retrieve the classes by contained within the namespace by querying the meta_class element, and it’s interesting to note that the returned elements are actually ManagementClass objects.

NamespacesNode

NamespacesNode is a container for all the namespaces contained within a namespace.

protected override System.Collections.IList GetNodeChildren()
{
    List<NamespaceNode> result = new List<NamespaceNode>();
    ObjectGetOptions options = new ObjectGetOptions();
    ManagementPath path = new ManagementPath("__NAMESPACE");

    ManagementClass managementClass = new ManagementClass(ManagementScope, path, options);
    using (managementClass)
    {
        ManagementObjectCollection instances = managementClass.GetInstances();
        using (instances)
        {
            foreach (ManagementObject mo in instances)
            {
                string namespaceName = mo.GetString("Name");
                NamespaceNode namespaceNode = new NamespaceNode();
                namespaceNode.Parent = this;
                namespaceNode.Name = namespaceName;
                result.Add(namespaceNode);
            }
        }
    }
    return result;
}

We populate the NamespacesNode by retrieveing all the instances of the "__NAMESPACE" class within the namespace.

ClassNode

A ClassNode represents a ManagementClass object.

A ClassNode represents a ManagementClass object, providing access to the properties, base class, descendants and qualifiers for the WMI class.

If you select a class in the hierarchy, you can query the data for that class by accessing the File -> New -> Query command from the menu.

So far this has proven to be a useful utility, and in the next article we will take a closer look at how CIMTool presents the data it retrieves from a query.

History

  • 1. of February, 2013 - Initial posting.
  • 2. of February, 2013 - Added binaries
  • 17. of February, 2013 - Now with code generation

    Just right click on a class in the treeview, and select 'Generate Class' from the popup menu.

    The code has gone through a thorough refactoring, and the code generator is based on the original MS code generator, which will change.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here