WMI is a powerful technology widely used by programmers to manage computers. It can be accessed in .NET through the
System.Management namespace. Although WMI classes are highly structured, the common way to use it is through WQL requests returning variant objects. The purpose of the WMIwrapper project in this article is to provide classes equivalent to WMI ones provided in the
root\CIMV2 namespace. It implements many classes with their properties and methods, so that the programmer will not rely on WQL strings (such as
SELECT * FROM Win32_LogicalDisk) that cannot be verified at compilation, but will use Intellisense in the Visual Studio GUI to get objects, properties, and methods.
The demo application is a quick and dirty proof of concept. First, connect to a computer with the File / Open menu ("." is the default value for the local computer) and navigate in the tree of objects (not all classes are included, refer to the help file for a complete reference). The right pane of the screen displays all the properties and their values returned by the native WMI class for the first instance found. The bottom of the screen displays a gridview with all the properties (arrays excluded) of the corresponding wrapper's class, one instance per line (for example, one line for each drive). Comparing the panels is a quick and efficient way to debug the wrapper.
The base class is
WMIobject. It does not exist in native WMI, but is used to provide general methods, mainly used to convert WMI types to .NET types and implement WMI methods. Other classes inherit from it, following the WMI architecture. For example (":" means "inherits from"),
WMIobject. Each class implements a part of the properties and methods used by the final one. As a rule of thumb, only the Win32-prefixed classes will be used outside the project.
The huge number of classes does not allow including a diagram in this article. You may use the Documentation.chm file, or create a class diagram to see the hierarchy of classes. The actual hierarchy of WMI classes has been respected, with minor adaptations, because WMI supports multiple inheritance, but .NET does not.
Classes go by two: each object class, say
CIM_System, has its corresponding collection class with the same name and a final s (
CIM_Systems). The collections mainly provide properties to find an item: the most common way to query WMI consists of filling the collection and then enumerating the items.
I added an extra class called
Computer to simplify access to the other classes. Its use is detailed below.
Using the code
Computer hardware and system
The simplest use of the wrapper is through the
Computer class. Connect to a computer with this code:
Dim ComputerName As String = "."
Dim _Computer As New WMIwrapper.Computer(ComputerName)
Your Windows account must have the necessary privileges to connect to a remote computer: either you are an administrator in a domain, or you have an account with the same login and password on both computers in a workgroup.
Since loading and running WMI takes quite a long time (usually a second or two), queries are not run by default. You must use methods to to this. The following code queries
Processors property contains a collection of
Processor objects. Loop through it to read their properties, such as
If _Computer.Processors IsNot Nothing Then
For Each Win32_Processor As WMIwrapper.Win32_Processor In _Computer.Processors
Refer to Documentation.chm to discover all the methods and properties of the
Computer methods allow managing file shares (this is not so easy with .NET):
GetShares fills the
Shares property, a collection of
Share objects. Each of them is a file or printer share on the computer, supporting properties such as
AccessMask and methods such as
DeleteFileShare allow creating or deleting file shares without calling
Shutdown methods are available.
GetOperatingSystem must have been called before.
Using the Win32 classes
Full WMI access is possible if you use the Win32-prefixed classes. Generally, you will fill a collection and then loop through it:
Dim _Processors As New WMIwrapper.Win32_Processors(ComputerName)
If _Processors IsNot Nothing Then
For Each Win32_ProcessorI As WMIwrapper.Win32_Processor In _Processors
The collection constructor allows using the key values of the classes to select a single item, or to pass a WQL condition:
Dim _Shares As New WMIwrapper.Win32_Shares(ComputerName,"Admin$")
If _Shares IsNot Nothing Then
For Each Win32_ShareI As WMIwrapper.Win32_Share In _Shares
Dim _Volumes As New WMIwrapper.Win32_Volumes(ComputerName, , "Caption = 'C:\\'")
If _Volumes IsNot Nothing Then
For Each Win32_VolumeI As WMIwrapper.Win32_Volume In _Volumes
A few classes are used differently. Security classes (
Win32_Trustee) do not belong to collections, and can be created from scratch. See the code of the
CreateFileShare function in Computer.vb to understand how to use them.
Methods are implemented. They return an
InvokeError object, with two properties:
Number (0 for success) and
Points of interest
Similar code can be obtained using MgmtClassGen.exe with less effort, but this tool generates a class for each WMI class, including all the necessary code. If you have an intensive use of WMI, you get a lot of redundant code, which should be put in base classes. That's what
EasyWMI is a similar project, developed in parallel.
WMIwrapper is just closer to the original WMI architecture, so I hope it will be easier to maintain in the future. I think it is easier to use because the documentation has been the object of all efforts.
I used TechNet as a reference for classes. Microsoft's WMI tools, especially WMI CIM Studio is the most convenient way to understand inheritance.
I used Sandcastle to compile the help file, through Sandcastle help file builder GUI.
This is an endless project because some classes are still missing and WMI evolves with new versions of Windows. You may find a few
'TODO comments in the code for non essential methods (I do not think WMI is the best way to create a folder, for example), I will fill them when I have time. Anyway, future versions are planned.
- Version 1.0: first public version.