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.
Windows Management Instrumentation: A Simple, Powerful Tool for Scripting Windows Management
This article assumes you're familiar with VBScript, Windows Script Host
Level of Difficulty 1 2 3
Code for this article: Boshier0400.exe (34KB)
SUMMARY The new Windows Management Instrumentation (WMI) technology for Windows 2000, Windows NT 4.0, and Windows 98 provides powerful scripting technology that can be used to administrate Windows-based systems. With WMI, you can create scripts to simplify management of devices, user accounts, services, networking, and other aspects of your system. This piece will introduce you to WMI and the WMI Scripting Object Model, taking a look at the available objects, methods, and properties. Along the way, you'll see how these elements can be used to create system management scripts.
hat do printers, services, processes, network adapters, files, keyboards, and disk drives have in common? One answer is that they are all key components of your computer system. But did you know that they are also a tiny subset of items that can be easily managed through a single scriptable interface?
WindowsÂ® Management Instrumentation (WMI) is much more than just a scripting technology. It's a simple yet powerful tool for scripting the management of your Windows-based system. In this article you'll learn about the power and extensibility of the WMI infrastructure, and the enormous range of management information that you can script today through WMI.
Using WMI, you can create scripts that control the following aspects of your system:
Server, workstation, and system management You can write scripts to manage computers, services, drivers, devices, file systems, DNS and DHCP servers, and Windows NTÂ® Event Logs. In addition, you can create scripts for network configuration tasks such as starting and stopping system services, listing and monitoring system drivers, listing records in the Windows NT Event Logs, and so on.
Security and user management You can write scripts to list account information pertaining to a specific domain user or domain group, or to list directory permissions.
Network management You can write a WMI-based script that will list the configuration details of network adapter cards on a specific computer.
Printer management You can write scripts to monitor printer status or printer tray empty events on a specific printer, to display the configuration of all locally connected printers, and so on.
System health monitoring You can create scripts to monitor and display the Windows NT Event Log entries that have been added to local event log files, as well as scripts that monitor the Windows NT System Monitor log files.
A Whistle-stop Tour of WMI
WMI is part of the Windows 2000 operating system, and is also available for Windows 98 and Windows NT 4.0 (Service Pack 4 and above). As an enabling technology, WMI provides a unified, extensible model in which all aspects of management information may be described, and also gives you unified scriptable access to that information.
In Windows 2000, WMI exposes management access to a vast array of information (see Figure 1). To see how this information is exposed, let's look at some of the architecture and concepts behind WMI. The key concepts are those of the model used to describe all information exposed through WMI as well as the components that make up the WMI architecture.
The Common Information Model
All management information exposed through WMI is described using the Common Information Model (CIM). Created by the Distributed Management Task Force (see http://www.dmtf.org), CIM is a standard, unified, object-oriented framework for describing physical and logical objects in a managed environment. To provide a common framework, CIM defines a series of objects with respect to a basic set of classes, classifications, and associations.
CIM includes three information models: core, common, and extension. In core models, classes are applicable to all management domains. The classes in the common models are common to specific management domains, independent of particular technologies or implementations. Common domains include systems, applications, devices, users, and networks. These models provide a basis for the development of system management applications, and include a set of base classes for extension into technology-specific areas. Finally, extension models represent technology-specific extensions of the common models. Extension models are specific to environments, such as operating systems.
To give CIM the coverage it deserves would require an article in itself, but there are five key points to note here.
- CIM provides the ability to encapsulate and classify managed objects by building on abstract classes to define physical or logical management elements. A few examples of managed objects are cables, software applications, or running processes.
- Relationships between objects can be modeled using the concept of an association, which is itself described as a CIM class. Windows NT service dependencies are an example of objects which can be modeled in this way.
- Classes are made of up properties and methods. For example, a class to model a hard disk might have a property that represents the free space available on the disk and a method to format the disk.
- Actual management information is exposed as instances of CIM classes. There might be three instances of the class that represents a disk on my host: one representing my hard drive, one my floppy drive, and the third my CD-ROM drive.
- Classes and instances live in namespaces. A namespace represents a logical scope for classes and instances.
The WMI architecture consists of a management infrastructure and WMI providers (see Figure 2). A management infrastructure includes the CIM Object Manager (CIMOM) and a central storage area for management data called the CIMOM object repository. The CIMOM provides applications with uniform access to management data. WMI providers function as intermediaries between CIMOM and managed objects. Using the WMI APIs, providers supply CIMOM with data from managed objects, handle requests on behalf of management applications, and generate event notifications.
Figure 2 WMI Architecture
Two particular aspects of the architecture make writing powerful applications (including scripts) to WMI easy. First, providers hide the details of specific instrumentation sources (Win32Â® APIs, SNMP, and so forth) from CIMOM, presenting everything according to a unified model. WMI is extensible, allowing more providers to be added into this architecture seamlessly. In addition, CIMOM hides the capabilities of specific providers from WMI-based client applications, presenting a uniform set of capabilities (data retrieval and update, query, method execution, and events) through a single API irrespective of the capabilities of the underlying provider.
Using WMI technology, you can create management applications that perform numerous tasks, such as displaying system information, generating an inventory of network resources, and processing and responding to events. WMI supports various strategies for creating management applications (C/C++ COM clients, automation clients, and so forth), but in this article I'll focus on clients that support Visual BasicÂ® or scripting.
Say "Hello World"
Following the maxim that a code sample is worth a thousand words, let's see what can be done with a very simple Windows Script Host (WSH) script using WMI. Enter the following into a text file and give it a .vbs extension:
for each Process in GetObject
WScript.Echo Process.Handle, Process.Name
When I ran this script on my host using cscript.exe, the following output appeared:
0 System Idle Process
This script is actually accomplishing three separate tasks: connecting to WMI, retrieving WMI-managed objects, and accessing the properties of WMI-managed objects.
GetObject ("winmgmts:") is used to make the connection to WMI. This returns a connection object called SWbemServices to a namespace. The moniker passed to GetObject can include information about which namespace on which server to connect to. In this example, I omitted this and connected to the default server (always the local host) and the default namespace (configured as root\cimv2 by default).
Retrieval of the managed objects is accomplished by calling the InstancesOf method of SWbemServices. This method takes as a parameter the name of the CIM class whose instances are to be returned. Here it's Win32_Process, which is the class that represents a Windows process. The instances are returned in a collection, which is why you can write a for eachï¿½next loop to access each individual instance.
Finally, inside the loop, the Process variable represents a single CIM object (SWbemObject) that in this case is a single running process on the host.
If you look carefully at this example, you'll see that something subtle, yet quite powerful, is happening. When executed, the following line displays the value of the Handle and Name properties of the Win32_Process class:
WScript.Echo Process.Handle, Process.Name
You access these properties the same way you would access any automation property on an Automation object. The difference here is that the set of properties is dynamic and depends on the definition of the underlying CIM class. This runtime binding of CIM properties (and methods) to automation properties (and methods) of SWbemObject is known as direct access, and makes scripting to WMI very intuitive.
The WMI Scripting Object Model
Now that you've seen an example of WMI scripting in action, let's look into WMI scripting in more detail. Figure 3 shows the principal objects and their relationships within the WMI Scripting Object Model. The green boxes represent the objects that can be created directly (using the CreateObject call in VBScript, for example), while the red boxes can't. The blue boxes represent objects that can be created using a moniker (via the GetObject call in VBScript, for example). Rectangular boxes are individual objects, while oval boxes represent automation collection objects.
Figure 3 WMI Scripting Object Relationships
An arrow from object A to object B signifies that you can obtain a B object by calling a method or accessing a property of an A object. I'll concentrate on the objects that are most often used for scripting purposes.
The SWbemLocator object is used to connect to a namespace. You'll often just use GetObject to do this, but when you need to fine-tune the parameters to the connectionâ€"perhaps when you need to specify an explicit user name and passwordâ€"then this is the object to use.
The following sample code connects to the root\default namespace on server erewhon with the user name samuel and the password butler:
set wmiLocator = CreateObject ("WbemScripting.SWbemLocator")
set wmiService = wmiLocator.ConnectServer
("erewhon", "root\default", _"samuel", "butler")
The ConnectServer call returns an SWbemServices object that represents a connection to WMI. I'll look at this object in more detail shortly.
The SWbemServices object represents a single connection to a WMI namespace. Usually you get one of these objects by calling GetObject. The methods and properties of SWbemServices are shown in Figure 4. Note that all of the methods have an asynchronous counterpart (such as DeleteAsync) that allows you to call them asynchronously.
The following sample code connects to the root\default namespace on server erewhon, using the credentials of the currently logged in user:
set wmiService = GetObject ("winmgmts:\\erewhon\root\default")
Here's how to execute a query to retrieve the name of all running Windows NT Services on the local host:
set wmiService = GetObject ("winmgmts:")
set runningServices = wmiService.ExecQuery _
("select Name from Win32_Service where State = 'Running'")
You should note that the SQL-style query allows you to select which properties are returned and to express a filter condition on the value of a property.
The SWbemObject object represents a single CIM class or instance. Usually you get one of these objects by calling GetObject or by iterating through an SWbemObjectSet collection.
The following sample connects to the root\cimv2 namespace (the default) on the local server with the credentials of the currently logged in user and retrieves the instance of Win32_Service that represents the DHCP service:
set wmiService = GetObject ("winmgmts:Win32_Service='DHCP'")
The value passed to GetObject in this example uses what is known as an object path to name an instance of the Win32_Service class. In this case you supply the value of the Name property of the class. In general, each CIM class has a set of key properties that are used to name the instance. If there's only one key for a class, you can omit its name and assume that it's the default value. The full form of the GetObject call would look like this:
set wmiService = GetObject ("winmgmts:Win32_Service.Name='DHCP'")
Don't worry if constructing these paths is starting to look a little tricky. WMI has an object called SWbemObjectPath that's designed to make this easy.
The static properties and methods of the SWbemObject object are shown in Figure 5. Note that all of the methods have an asynchronous counterpart (such as PutAsync_) that allows you to call them asynchronously.
As you saw earlier, it's important to note that not only does SWbemObject have a set of static (compile-time) properties and methods, but any bound instance of SWbemObject will, at runtime, dynamically expose automation properties and methods that correspond to the properties and methods of the underlying CIM class. This is why all the static properties and methods end with an underscore character; since CIM names cannot end with an underscore, you're guaranteed to be free of name collisions between static and dynamic names.
The following sample illustrates how to display the names of all associated objects of the C drive on the local host:
set disk = GetObject ("winmgmts:Win32_LogicalDisk='C:'")
for each associator in disk.Associators_
Remember my advice not to worry about constructing object paths by hand? Well, notice in the previous sample that the DisplayName property (of SWbemObjectPath) provides the string representation of the path to the object. This property value can be passed as the parameter to GetObject in order to retrieve the object.
Here's another example. It uses method execution to shut down a server remotely:
set osSet = GetObject ("winmgmts://erewhon").InstancesOf _
for each os in osSet
Here, Win32Shutdown is a CIM method of the Win32_OperatingSystem class.
Finally, this sample creates a new process instance of Notepad:
set processClass = GetObject ("winmgmts:Win32_Process")
retVal = processClass.Create ("notepad.exe")
The Create method used here is a static CIM method of the Win32_Process class, so you would call it on the class rather than on an instance.
The SWbemSink interface is implemented by client applications to receive the results of asynchronous operations and event notifications. To make an asynchronous call, you must create an instance of an SWbemSink object and pass it as a parameter to any asynchronous WMI call.
The events in your implementation of the SWbemSink object are triggered when either status or results are returned or the call is complete. Figure 6 shows the methods and properties of this object.
SWbemSink uses the standard connection point container paradigm, so it integrates cleanly with the usual mechanisms for providing event callbacks in MicrosoftÂ® Internet Explorer, Visual Basic, and Windows Script Host 2.0.
The Dynamic HTML sample code shown in Figure 7 illustrates how to receive and display the name of the WMI service asynchronously once the user clicks on the document. Notice that <OBJECT> tags are used to create an SWbemLocator and an SWbemSink, and that the implementation for SWbemSink is defined by specifying <SCRIPT> tags for the OnCompleted and OnObjectReady events.
The binding of the sink to the call is accomplished by passing the mysink object as a parameter to the SWbemServices::GetAsync call. The objObject parameter to the latter event is an SWbemObject returned from the asynchronous call that represents an instance of the Win32_service class, and DisplayName is a CIM property of that class.
A Word about Security
As you've seen, you can do powerful things with WMI, but with power comes responsibility. When you call WMI from a script, all of the things that you do through the Scripting API are done using your security credentials. (This concept is known as impersonation among those who really know their Windows NT security.) This means that WMI lets you do exactly what you, the user, can legally doâ€"no more, no less.
The examples I've presented here assume that impersonation of the client happens automatically. However, note that in versions of WMI before Windows 2000, this was not the case. Instead, the client would specify an impersonation level explicitly, by setting the SWbemSecurity.ImpersonationLevel property of SWbemServices, for example.
All of the creatable WMI scripting objects are marked as unsafe for scripting, which means that you or your users will have to change the browser security settings to enable such controls if you use WMI scripting in a Web page. This is a security feature, since WMI is a powerful technology that can access and configure many aspects of the operating system.
In this article I've only touched on some of the tasks you can accomplish with scripting and the WMI. Now you can go on to build your own solutions. Don't forget to look through the WMI SDK documentation for more information.
For related articles see:
Alan Boshier is a developer on the Windows Management Instrumentation team at Microsoft. Hailing from the United Kingdom, he lives in Seattle where the rain makes him feel at home. When not writing script, his goal is to read* Finnegans Wake *again, and this time understand it.
From the April 2000 issue of MSDN Magazine.