This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
For more in this issue on WMI: |
|||||||||||||||||||||
Windows Management Instrumentation: |
|||||||||||||||||||||
Jeffrey Cooperstein | |||||||||||||||||||||
|
|||||||||||||||||||||
ne of the greatest challenges facing an enterprise developer is the management of computer networks as they become larger and more complex. Windows® Management Instrumentation (WMI) is a powerful technology that makes it possible to manage a single machine, or ten thousand all at once. Unfortunately, WMI is probably one of the best-kept secrets to come out of Microsoft in recent years. It hasn�t received much coverage compared to technologies such as Active Directoryâ„¢ or Windows DNA. This article will take you on a tour of WMI, so you�ll have the background you need to write your own applications using WMI. Before long you�ll be convinced that WMI should be as much a part of every developer�s vocabulary as COM, Win32®, or Microsoft. OverviewWMI is one of several technologies introduced by Microsoft to support the management of systems in an enterprise. Active Directory provides location, policy, and organizational information on an enterprise-wide level. The Microsoft® Management Console (MMC) is the presentation framework for writing management apps. Windows Script Host (WSH) allows administrators to automate complex tasks. And finally, WMI is the technology that enables remote management of Windows-based systems and apps.WMI allows developers to use a simple, consistent mechanism to query for information or configure settings on computers across an enterprise. The amount of information available through the WMI interface is staggeringâ€"hardware settings, performance information, driver configuration, BIOS information, application settings, event log information, and much more. WMI gathers information from a diverse set of APIs, but it presents information following a simple, industry-standard management object model. This makes it unnecessary for application developers to learn the specifics of every API set provided by Windows. To understand this power, consider a developer who wants to enumerate the descriptions for four different groups of objects on a machine: services, printers, processes, and CPUs. Without WMI, a developer has to find and learn different APIs to accomplish each type of enumeration. With WMI, it�s remarkably simple because every object class is enumerated in the same way. Just take a look at how simple this task can be completed with the VBScript code for the WSH shown in Figure 1. If you are running Windows 2000, you can copy this code to a file ENUM.VBS, and run the command cscript ENUM.VBS from a console window. If you encounter an error, it�s most likely because I�ve omitted error checking for null to keep the script short. For example, if there is no comment listed for one of your installed printers, obj.Description will be returned as null. If you are running Windows 9x or Windows NT® 4.0, WMI is an optional component. The most recent version of WMI is available from the Microsoft Web site (https://msdn.microsoft.com/downloads/default.asp?URL=/code/topic.asp?URL=/MSDN-FILES/028/000/015/topic.xml). Remarkably, the script in Figure 1 could be used to enumerate the same information for a remote machine. To show the information about MYSERVER, simply use WinMgmts://MYSERVER as the parameter to GetObject in the first line. In fact, any information that is exposed to WMI is automatically available using the same API from a local or remote machine. Although some Win32 APIs provide the ability to specify a remote machine, others only provide access to the local machine and will leave you stranded if you try to get the information about a remote system. WMI also makes it simple to set information or invoke actions on managed objects. The same syntax can be used to stop a service, terminate a process, or log a user off a remote machine. The developer only needs to know the name of the object and the name of the action. There�s no need to learn a new API. To top everything off, an event infrastructure provides change notifications for all objects exposed through WMI. Later in the article I�ll show a sample that monitors processes being created or destroyed. Another sample generates a notification whenever a floppy disk is inserted or removed. The same techniques can be used on any type of object managed through WMI. Even when the underlying API doesn�t provide this sort of notification for an object, the WMI architecture transparently simulates the behavior by monitoring the instances. Again, remote access to all this functionality is provided for free by the WMI service. In addition to the information already exposed through WMI, applications can also expose their own custom objects and events. Once this is done, any WMI management application will be able to manage your application as well. This can include remote configuration, change notifications, or receiving of custom events. The Genesis of WMIWMI is a Microsoft technology, but it is built on industry standards introduced in recent years. Understanding WMI requires understanding its evolution from an initiative called Web Based Enterprise Management (WBEM). Several years ago, a group of computer companies established the WBEM initiative to develop standards for managing enterprise systems and devices. The goal was to develop a single set of standards for managing any component of an enterprise network. This would ease the problems caused by the existence of many separate standards, such as SNMP for network devices and DMI for desktops. In the future, companies would develop WBEM-compliant hardware, software, and systems that could all be managed in the same way. Thus a single management application could easily manage all the diverse components in an enterprise environment. Eventually the responsibility for the WBEM initiative was assumed by the Desktop Management Task Force (DMTF) organization. The DMTF is responsible for maintaining the standards that will help meet the goals of the WBEM initiative.CIM ClassesThe first standard from the WBEM initiative is a method for describing management information called the Common Information Model (CIM). CIM takes an object-oriented approach to modeling information. Management information is expressed using class definitions, inheritance, instances, properties, and methods. CIM classes are defined in text files using the Managed Object Format (MOF). A complete coverage of the MOF file format is well beyond the scope of this article, but its syntax is fairly intuitive if you are familiar with C++, the Java language, or Interface Definition Language (IDL). Here�s an example of how to define a class and two of its subclasses:
The previous MOF file defines an Automobile as a base class with two subclasses: Car and Truck. An Automobile has a Make property, a Model property, and a Recall method. A Car has an additional property, BlueBookValue. A Truck has an Axles property, with a default value of 2. (New instances of Truck will have a value of 2 for Axles unless otherwise specified.) The words in brackets (abstract and key) introduce the CIM concept of qualifiers. Qualifiers can be applied to the entire class, a property, a method, or even an individual method parameter. Qualifiers are similar to the concept of attributes in IDL files. They provide additional descriptive information about the use of a class, property, or method.
The CIM standard alone is not enough to enable companies to create manageable objects and prevent chaos. For example, one company might call a router a NetworkRouter while another company calls the same thing a Router. Even worse, two companies could attempt to define a Router with the same class name, but different properties. To prevent this sort of confusion, the DMTF also defines the CIM schema. A schema is a well-defined collection of class definitions that all companies agree to follow. Classes that are a part of the CIM schema start with CIM_ by convention (such as CIM_Battery or CIM_Process). The CIM schema makes heavy use of inheritance to allow management applications to treat groups of similar objects in the same way. For example, CIM_Battery, CIM_Printer, and CIM_Processor are all derived from the base class CIM_LogicalDevice. This allows management applications that know how to work with a CIM_LogicalDevice to manage any type of device derived from that class. In addition, any derived class will support the properties and methods of the base class. The class CIM_LogicalDevice has a property that specifies if power management is supported (PowerManagementSupported), and a method that allows the power state to be set (SetPowerState). By exposing this functionality in the base class, applications can manage the power state for a printer, processor, or any device derived from CIM_LogicalDevice. WBEM SupportThe CIM and MOF standards and the CIM schema are the core components of the WBEM initiative. These standards are platform- and implementation-neutral. To make universal management a reality, hardware and software vendors must create systems that support these standards (referred to as implementations of WBEM). This involves exposing management functionality through classes derived from the CIM schema. The Microsoft implementation of the WBEM initiative for the Windows operating systems is WMI.Microsoft is not alone in supporting WBEM. Hardware companies have committed to providing network and storage devices with implementations of WBEM. Sun has promised a WBEM implementation for Solaris. Major players in management software, such as Tivoli Systems and Computer Associates, have committed to supporting WBEM in their applications. With all this support, enterprises that can be managed in a single consistent manner will certainly become a reality. WMI ArchitectureTo understand the components of the WMI architecture, shown in Figure 2, it helps to analyze the creation of an implementation of the WBEM standards. The first task is to decide which elements of the CIM schema apply to a computer running Windows. The next step is to extend the CIM schema by defining classes that expose any additional information available under Windows. The convention used by Microsoft is to derive from CIM classes and prefix the class name with Win32_ (for example, the Win32_NetworkAdapter is a class derived from CIM_NetworkAdapter). Eventually you need to write some software that actually provides the management capabilities. It will have to maintain the list of supported classes, and provide the actual data when instances of a class are requested. It will also have to respond to method calls on objects by implementing the requested actions. In generic terms, this is called a CIM Object Manager (CIMOM). On Windows NT, the CIMOM resides in a service called WinMgmt, and is implemented in WinMgmt.exe. Although Windows 9x does not support Windows NT services, the CIMOM is still implemented in an executable called WinMgmt.exe.At some point, you need an API that allows you to talk to the CIMOM. You need to be able to query the schema, enumerate instances, and call methods. Although the CIM standard defines the content to be included in classes, there is no definition for its binary representation or the mechanism that�s used to access it. You are free to use DLLs, COM, sockets, named pipes, and so on. Microsoft chose to expose the CIMOM functionality through a set of DCOM interfaces. These interfaces all start with IWbem (such as IWbemServices or IWbemClassObject), and are documented in the Platform SDK. These interfaces make it possible to write management applications that work with classes and instances that are managed by WMI. By choosing DCOM, Microsoft could essentially make any interface to the CIMOM accessible from remote machines without writing a single extra line of code. In reality, though, the overhead of sending every interface call to the remote machine would cripple the performance of clients. In addition, the information returned by the interfaces includes a large amount of redundant information and would waste bandwidth. For example, every WMI object includes a property that specifies the machine where the object exists. An interface method that returns an array of objects will include the same machine name for every element. Relying on DCOM to marshal the data would result in the machine name being sent over and over. To improve performance, Microsoft developed sophisticated custom proxies and stubs to compress information and minimize this overhead. Although developers won�t know that these proxies and stubs exist, they are responsible for the awesome performance of remote connections. Once you�ve defined the DCOM interfaces that allow access to the CIMOM, the next step is to create a database that holds the class definitions. In addition, you need to store a lot of static information such as the security settings for WMI itself. Static information is data that does not change except when manipulated by the CIMOM directly or indirectly through calls to the DCOM interfaces. This can include static instance data as well class definitions, allowing configuration information to be stored in much the same way that static information is stored in the registry today. The WinMgmt service maintains this static information in a database called the CIM Object Repository, which is a single file in the \winnt\system32\wbem\respository directory. To provide information about dynamic objects, the WinMgmt service supports the registration of providers. WMI providers are actually COM servers that support a set of well-defined interfaces described in the Platform SDK. Providers can be queried on demand by the CIMOM for dynamic information, or they can explicitly call the CIMOM to inform it of changes to data. The most common use is to provide dynamic instance information, such as the list of active processes. It is also possible to write providers that dynamically describe classes in the schema, or providers that generate event information (the event architecture will be discussed later). WMI ships with several providers that supply information for an amazing number of classes in the schema (see Figure 3). Developers can extend the information provided through WMI by defining custom classes and writing providers to supply dynamic instance information. The DCOM interfaces provided by the WinMgmt service are enough to start C++ developers writing management applications, but unfortunately not all development environments support access to arbitrary COM interfaces. To access WMI from environments that support Automation objects, Microsoft provides scripting objects that wrap the direct DCOM interfaces. There is a fairly straightforward mapping between the DCOM interfaces and the scriptable objects. For example, SWbemObject wraps IWbemClassObject, and SWbemServices wraps IWbemServices. The naming conventions are not identical, but anyone familiar with one interface can easily identify and understand the other. The scripting objects allow complete access to WMI through Visual Basic®, Visual Basic for Applications (VBA), WSH, VBScript, JScript®, ASP, or any other environment that supports automation objects. Visual Basic or VBA projects can access these objects by adding Microsoft WMI Scripting V1.1 Library in the References dialog. Platforms that support ActiveX® scripting can create these objects by their class ID or by their class name, which is prefixed with WbemScripting such as WbemScripting.SWbemLocator. Another component provided by Microsoft wraps access to the DCOM interfaces. It is an ODBC adapter that makes classes, properties, and instances look like tables, columns, and rows for database applications. This is useful when incorporating WMI data into Microsoft Excel spreadsheets, ActiveX Data Objects (ADO) applications, or other database-driven apps. The remainder of this article discusses the use of WMI through either the DCOM interfaces or the scripting objects. Both of these methods provide full access to the services of WMI, while the ODBC adapter currently only supports a subset of the WMI functionality. Although this article doesn�t cover the use of XML, it is an extremely important feature to watch in the future. As mentioned earlier, the WBEM initiative does not specify the use of a particular technology to access CIM objects. Microsoft chose to use DCOM interfaces, but it is unlikely that other operating systems or hardware devices will do the same. Instead, XML provided by HTTP connections will most likely be adopted as a standard way of interfacing with WBEM implementations. In fact, the DMTF has taken on the task of creating an XML/HTTP standard for WBEM implementations. Microsoft is also expected to support an XML standard in the future. This will allow applications to query for WMI data using HTTP with the results returned in XML. Future hardware devices and OSs will also support management through XML and HTTP. NamespacesWMI supports the grouping of a collection of classes into logical units called namespaces. Namespaces are arranged much like folders on a drive, and class definitions are like files in these folders. Figure 4 shows an example of how namespaces are presented with the WMI tools in the Platform SDK. Every machine has a well-defined namespace at the top of the hierarchy called the root namespace. The location of a namespace is described with a path, just like child directories (such as root\cimv2 or root\directory\LDAP). Each namespace contains its own collection of classes and instances. To uniquely specify a class, the namespace must also be specified (such as root\cimv2:Win32_Processor). Within a namespace, all the class names must be unique (just like files in a directory), but it�s possible to have unrelated classes in different namespaces with the same name. Inheritance is a critical part of CIM, and one restriction is that all classes derived from a common base class must be defined in a single namespace. In other words, if you want to define a Car derived from an Automobile, the Automobile class must be defined in the same namespace.
As mentioned earlier, one of the core components to the WBEM initiative is to support the classes defined in the CIM schema. In WMI, these classes can be found in the root\cimv2 namespace. The CIM schema is continually updated, but each release is described with a version number. The v2 part of the root\cimv2 namespace means that the schema represented is the CIM Version 2 schema. Microsoft has also developed custom schemas for information not represented by the CIM V2 schema. These schemas are stored in other namespaces, such as root\WDM for information provided by WDM drivers, or root\directory\LDAP for information provided by the Active Directory provider. Developers who are providing their own schemas can create new namespaces. In fact, unless you are extending a schema by deriving from an existing class, it is best to create new classes in your own namespace. System Classes and System PropertiesEvery namespace contains a common set of classes called system classes. System classes all have names that start with a double underscore (such as __Provider). One interesting system class in each namespace is the __NAMESPACE class. This class has a single property, the Name property. Enumerating the instances of this class provides the mechanism for discovering child namespaces. For example, the root namespace will have a __NAMESPACE instance with the Name property set to cimv2. This means that a namespace called root\cimv2 exists. Other system classes are used for relatively sophisticated WMI programming that will not be covered in this article, such as custom provider registration.In addition to system classes, there�s a standard set of system properties that can be found on every class. Again, they are easy to identify because they always start with a double underscore. The properties are read-only, and are generated automatically by WMI. They exist mostly to allow client applications to dynamically determine the identity of an object. When describing class or instance definitions in MOF files, these properties are omitted. Figure 5 shows a list of the system properties. Object PathsThe syntax shown in the previous section for describing namespaces and classes introduces the concept of object paths. An object path is a way of specifying a machine, namespace, class, or instance. The absolute form of an object path specifies a machine name as well as the namespace. For example, \\jeffc\root\cimv2: Win32_Process refers to the class definition of Win32_Process in the root\cimv2 namespace on the machine \\jeffc. Object paths are considered relative if they omit the machine name or namespace. The path root\cimv2:Win32_Process refers to the Win32_ Process in the root\cimv2 namespace on the current machine. The path Win32_Process refers to the class definition of Win32_Process in the current namespace on the current machine.Object paths are used to specify instances as well as class definitions. To specify an instance, the key properties and their values are specified after the class name. The relative object path
refers to the instance of Win32_Environment where the Name property is TEMP and the UserName property is JEFFC\Administrator. Note that the \ was expressed as \ when quoted in the object path (just like C++ or the Java language). In the case of singleton classes (which have no key properties, but one and only one instance), the object path consists of the class name appended with =@, such as \jeffc\root\cimv2:SingletonTest=@. Programming WMIIt�s now time to get down to the specifics of writing management applications with WMI. The first step for any application using WMI is to get an IWbemLocator pointer using CoCreateInstance with CLSID_WbemLocator. If you are using the scripting interfaces, you are creating a WbemScripting.SWbemLocator object. From this point on, I�ll present the samples using JScript and the scripting interface. This will make it easier to understand and read the samples. I�ll mention the equivalent DCOM interfaces where appropriate, so it should be easy to convert over to C++ at a later time.The locator object allows you to request a connection to the WMI service through the ConnectServer method. ConnectServer lets you specify a machine name and namespace, or it will connect you to a default namespace on the local machine if left blank. ConnectServer returns an SWbemServices object (or IWbemServices interface). The SWbemServices object provides communication to the CIMOM, but it can only access objects in the namespace specified by ConnectServer. To get objects for a different namespace (even if it is on the same machine), you�ll need to get a different SWbemServices object from another call to ConnectServer. SWbemServices provides many methods for getting WMI objects, but the simplest is Get (or IWbemServices:: GetObject). This allows you to use an object path to get a class definition or a specific instance. Figure 6 shows an example of what you�ve seen so far. In Figure 6, you�ll notice that the Get method was used to retrieve the class definition of Win32_LogicalDisk, as well as an instance of Win32_LogicalDisk for the C: drive. In both cases, you are returned an SWbemObject (or IWbemClassObject interface when using IWbemServices::GetObject). The SWbemObject gives you access to the full definition of the object, including properties, values, methods, and qualifiers. The scripting object dynamically appends the CIM object�s properties to standard properties supported by SWbemObject. This makes it easy to access properties if you know what you are looking for in advance. The following shows how to access the FreeSpace property of the C: drive instance you obtained previously:
Property names and values can also be accessed through the Properties_ collection:
Methods are accessed in a similar manner. Methods can be accessed through the Methods_ collection, and they are also appended directly onto the SWbemObject itself.
Until now, the examples have assumed that you know the object path of the class or instance you want to examine. The SWbemServices object also allows you to dynamically query for available classes or instances. The list of available classes can be determined through the SubclassesOf method. This method returns the subclasses of a given class or the list of base classes if no class is specified as an argument. To allow for instances to be retrieved dynamically, WMI again borrows a technique from the database world; it uses a variation of SQL called the WMI Query Language (WQL). Here�s an example of a simple WQL query that retrieves the list of all logical drives:
Just as with SQL, WQL queries can be refined to return a specific set of properties, or a subset of instances that satisfy some criteria. The full syntax of WQL queries is documented in the Platform SDK, but some examples can help show the power of WQL. The following query returns the list of all services that are stopped:
This query returns only the Name and FreeSpace properties of all logical disks:
To execute a WQL query, you can use the ExecQuery method of SWbemServices. The ExecQuery method will return a collection of objects that meet the criteria specified in the query. The following sample will output the name, free space, and total size for every logical drive:
If you run the previous script from a console window (using the command cscript SAMPLE2.JS), the output will look something like this:
Each line should show the drive name, free space, and drive size, but you�ll notice that the drive size is missing. If you look carefully at the WQL query, you�ll notice that I only asked for the Name and FreeSpace property. Since I did not request the Size property, I�m not guaranteed that it will be available in the returned objects. Limiting a WQL query to specific properties can provide a great performance boost since providers can skip properties that are costly to query, but it can leave you with SWbemObject objects that only have partial information. This can be an annoying source of bugs if you are not careful.
The equivalent method without monikers requires three steps:
The use of GetObject with monikers can be very convenient for many simple tasks. However, repeated use of monikers for objects from the same namespace may be less efficient than it would be to reuse a single SWbemServices object. A full list of all the options supported by WMI monikers is covered in the Platform SDK under the heading "Object Creation and Monikers."
CIM Studio is one of the most useful tools for exploring schemas in the WMI SDK (see Figure 7). The left pane shows the inheritance tree for classes in a namespace. The right pane shows class or instance information. CIM Studio also allows you to enter WQL queries and examine the results. SecuritySince WMI is a service, it runs as Local System with virtually unlimited control over the computer. When a client makes a request, it is this service that actually has to call Win32 APIs to get the information or perform the action. Does this mean that you can request information through WMI and essentially circumvent the usual Windows NT security that applies to your user account? Absolutely not.Whenever a connection is established, your user credentials are passed to WMI by the underlying DCOM infrastructure. WMI will impersonate your credentials before attempting to fulfill any requests. This ensures that you cannot perform any action that you would not otherwise be allowed to do. Consider the case of calling the Win32 DeleteFile function, versus using the Win32_DataFile�s DeleteFile method. If you�re calling the Win32 DeleteFile function, Windows NT is responsible for making sure you have the proper permissions. If you�re using the Win32_DataFile�s DeleteFile, you are asking the WMI service to delete the file. Eventually, the WMI service will have to call the Win32 DeleteFile function. Instead of trying to figure out for itself if you should be allowed to do this, WMI just impersonates you and attempts the call. Windows NT makes proper security checks and returns an error to WMI if you don�t have permission. WMI can then propagate the error back to the client application. When connecting to remote machines, it is possible to specify the credentials of another user as parameters to ConnectServer. If these are left out, the credentials of the current user are used instead. When you�re connecting to the local machine, only the credentials of the current user can be used. The previous explanations are an oversimplification of what really goes on, but it�s enough to get by on if you are writing client applications with the scripting objects. When using the DCOM interfaces, there are additional DCOM rules that apply. In particular, any interface that is remoted needs to be configured with the correct security blanket using IClientSecurity. For local connections, privileges for the client thread must be enabled to perform actions that normally require the privileges. The WMI SDK covers these issues in more detail, but it is worthwhile to invest in some good books on the finer points of DCOM. Fortunately, the scripting objects handle most of these complexities automatically, which makes them an excellent choice for DCOM novices.
To provide additional protection, WMI supports traditional Windows NT security on each namespace. This is useful to specify restrictions such as who will be able to connect to WMI from remote machines. This can be configured through an extension to the Computer Management snap-in on Windows 2000 (see Figure 8). To access this, right-click the My Computer icon on the desktop, and then choose Manage. Under Services and Applications, choose WMI Control, then display its properties. On the Security tab, you�ll be able to set the permissions for each namespace just as you set permissions for folders on your hard drive. If you are running Windows 9x or Windows NT 4.0, running WBEMCNTL.EXE will bring up the same utility. When connecting to a machine running Windows 9x, there is no support for Windows NT security on the objects managed through WMI. However, WMI allows namespaces to be configured with simulated Windows NT permissions. This lets an administrator control who connects to a namespace, but once connected, the client will essentially have full control over the objects exposed. EventsSo far you�ve seen how applications query WMI for information about classes and instances. WMI also allows applications to receive events from the system. Events are defined in the schema just as other classes. For example, a modem manufacturer could write a provider that exposed a MyModem_Ring event. The MyModem_Ring class could have properties, such as CallerIDName or CallerIDNumber. To register for an event, an application uses WQL with a syntax similar to data queries. The following event query specifies that an application is interested in incoming calls from Stephanie:
In addition to events defined by providers, applications can register for events that monitor changes in classes or instances. This is very powerful since it allows an application to respond to any change in state that is exposed through WMI. The code in Figure 9 shows how easy it is to monitor the creation of arbitrary objects. The HTML Application (HTA) watches for the creation of any new process. ConclusionAs you can see, WMI is a complex, powerful service. This article has just scratched the surface of what can be done with WMI today. As other companies adopt the WBEM standards, the power of WMI will be expanded even more. I hope this has encouraged you to look at WMI for your own applications. I think you�ll find that it will become an indispensable tool. |
|||||||||||||||||||||
For related articles see: Background information: From the May 2000 issue of MSDN Magazine. |