Microsoft® Windows® 2000 Scripting Guide
CIM classes are organized into namespaces. Namespaces are the partitioning mechanism employed by the CIM to control the scope and visibility of managed resource class definitions. Each namespace in the CIM contains a logical group of related classes representing a specific technology or area of management.
Namespaces are roughly equivalent to folders on a disk drive. Like folders, namespaces provide a place to store related information; a folder named Scripts is likely to contain scripts and a namespace named MicrosoftActiveDirectory is likely to contains WMI classes used to manage Active Directory. Both folders and namespaces help you to uniquely identify an item. You can have only one file on a computer named C:\Scripts\WMI_Script.vbs; likewise, you can have only one WMI class named root\cimv2:Win32_Process.
- One difference between folders and WMI namespaces is that folders are often deeply nested; for example, it is common to have folders such as C:\Program Files\Microsoft Office\Office\Office10. By contrast, namespaces rarely go more than three levels deep; the vast majority of classes useful in system administration scripts reside in the root\cimv2 namespace, a namespace nested only two levels deep.
All classes within a namespace must have a unique class name, and classes in one namespace cannot be derived from classes in another namespace. This is why you will find identical system, core, and common classes defined in multiple namespaces.
Most of the classes that model Windows-managed resources reside in the root\cimv2 namespace. However, root\cimv2 is not the only namespace you need to be aware of, as suggested in Figure 6.2. Although the Event Log, Performance Counter, Windows Installer, and Win32 providers all store their managed resource class definitions in the root\cimv2 namespace, the Registry provider stores its class definitions in the root\default namespace. This means that scripts that use the Registry provider will differ from scripts that use the Event Log provider, if only because the scripts must connect to different namespaces.
Specifying a Namespace
Every WMI script connects to a namespace as part of the initial connection step. For example, the following line of code connects to the root\cimv2 namespace on the local computer. (The connection is made on the local computer because no computer name is specified in the connection string.)
Set objSWbemServices = GetObject("winmgmts:root\cimv2")
A connection is made even when a namespace is not included in the connection string. For example, no namespace is included in the following line of code.
Set objSWbemServices = GetObject("winmgmts:")
If the target namespace is not specified, the script connects to the default scripting namespace. The default namespace is defined by the following registry entry:
The default namespace setting is to WMI scripting what the %PATH% environment variable is to the operating system. When you issue a command at the command prompt without specifying the fully qualified path of the command, the operating system uses the %PATH% environment variable to locate the corresponding executable file. For example, you do not have to type C:\Windows\System32\calc.exe to start Calculator. Why? Because the System32 folder is in the path. You can simply type Calc.exe, and the operating system will check the path, find the program, and start Calculator.
If the operating system cannot find the file, an error is generated.
Similarly, when you retrieve a managed resource in a WMI script, the WMI Service (winmgmts) searches for the managed resource blueprint (class definition) in the default namespace if no namespace is specified. If the WMI service cannot find the managed resource class definition in the default namespace, it generates a WBEM_E_INVALID_CLASS (0x80041010) error.
- Dont confuse the Default Namespace setting with the root\DEFAULT namespace. They are unrelated unless, of course, you set root\DEFAULT as your default namespace.
There is at least one difference between %PATH% and namespaces, however. The path can include multiple locations, even folders on different drives. The default namespace, by contrast, refers to a single location.
The root\cimv2 namespace is initially configured as the default namespace for scripting; however, the default scripting namespace can easily be changed. Because of this, you should always identify the namespace of a managed resource in your WMI scripts rather than assume that the default is root\cimv2. The following code snippet shows how to specify a namespace when connecting to WMI. In addition to specifying the namespace, the script also uses a variable, strComputer, to represent the name of the computer that the script should run against.
strComputer = "." Set objSWbemServices = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Why was strComputer set to the value dot (".")? In WMI scripting, the first part of the object path is always the name of the computer. If no computer name is specified or if a dot is found, the script runs against the local computer. Setting strComputer to dot does two things: 1) It causes the script to run against the local computer, and 2) it provides a placeholder that makes it easy to modify the script to run against a remote computer. For example, to run the script against a computer named WebServer, simply set the value of strComputer to WebServer:
strComputer = "WebServer"
Adding the target namespace to the connection string tells the CIMOM where to look for the managed resource class definition in the CIM, much as a fully qualified path tells the operating system exactly where to look for a file. When you specify the target namespace, the script does not first check the default namespace setting in the registry. Instead, it connects directly to the specified location.
- You might think that WMI could just search all its namespaces until it located the desired class. This cannot be done, however, because different namespaces can have classes with the same name. For example, WMI includes both a class named root\cimv2\__Event and one named root\default\__Event.
Managing the Default Namespace for Scripting
You can use the WMI scripting library in combination with the Win32_WMISetting class to read and change the default namespace for scripting, as demonstrated in Listing 6.8 and Listing 6.9. Win32_WMISetting is a dynamic class that models operational parameters for the WMI service. The writable property representing the default namespace for scripting is ASPScriptDefaultNamespace.
Listing 6.8 uses the same three WMI scripting steps connect, retrieve, and display that have been used all along, with one noticeable change. As recommended earlier, it specifies the fully qualified namespace for the Win32_WMISetting class in the WMI connection string passed to the VBScript GetObject function. Not only does this example follow the namespace recommendation in Listing 6.8, but this chapter will use qualified namespaces from this point forward. Doing this will help you avoid invalid class errors in your WMI scripts.
Listing 6.8 Retrieving the Default Namespace for Scripting Using WMI and VBScript
1 2 3 4 5 6 7 8 9 10
If you run this script under CScript on your local computer, you should see the default namespace of the local computer displayed in the command window, as in the following output.
Default namespace for scripting: root\cimv2
To set the default namespace for scripting, you can perform the same scripting steps as in Listing 6.8 with one important change: Rather than use the WMI to read a property of a managed object , you use WMI to:
Set the property value.
Call the SWbemObject Put_ method to commit the change to the WMI-managed resource.
The set and commit operations are performed inside the For Each loop because the InstancesOf method always returns an SWbemObjectSet collection. This is true even when there is only one instance of the target WMI-managed resource, as is the case with Win32_WMISetting.
Listing 6.9 Setting the Default Namespace for Scripting
1 2 3 4 5 6 7 8 9 10
Thus far the scripts in this chapter have used the same WMI scripting technique to retrieve instances of dynamic WMI-managed resources. For example, the same script template was used to retrieve total physical memory, services, and event log records. In Listing 6.6 through Listing 6.8, the same template was used to retrieve services, operating system information, and the default namespace for scripting. As it turns out, you can use the same WMI scripting technique to retrieve namespace information from the CIM. The only change you need to make to the script is the target class name.
Namespace information is stored inside the CIM as static instances of the __NAMESPACE class. The __NAMESPACE class is an example of the static class type defined earlier. Unlike dynamic managed resources that are retrieved on demand from a provider, static class instances are stored in and retrieved directly from the CIM without the use of a WMI provider. Listing 6.10 uses the __NAMESPACE class to retrieve and echo all of the namespaces directly beneath the root namespace.
Listing 6.10 Retrieving CIM Namespaces Using WMI and VBScript
1 2 3 4 5 6 7 8
The following output is the result of running the script on a Windows 2000based computer:
DEFAULT SECURITY CIMV2 WMI directory
The list of namespaces will vary based on the versions of both Windows and WMI installed on the target computer, and any WMI-enabled applications installed on the computer. For example, these namespaces are found on Windows XP with Microsoft® Office XP and the .NET Framework installed:
SECURITY RSOP Cli WMI CIMV2 MSAPPS10 Policy Microsoft DEFAULT directory subscription NetFrameworkv1
Listing 6.10 does not provide a complete picture of all of the namespaces available on the target computer. It retrieves and displays only the namespaces beneath a single specified namespace (in this case, root). To display all of the namespaces on a local or remote WMI-enabled computer, you need to modify Listing 6.10 to recursively connect to and enumerate each namespace. Fortunately, this is not as difficult as you might think, as shown in Listing 6.11.
Changing Listing 6.10 into a recursive namespace script primarily involves implementing the body of the original script inside a subroutine and providing a mechanism to call the subroutine for each namespace instance retrieved from the CIM. Listing 6.11 accomplishes this by performing the following steps:
Initializes the variable strComputer with the name of the target computer.
Calls the recursive subroutine, EnumNameSpaces, and passes the subroutine a string identifying the initial namespace as "root". The body of the EnumNameSpaces subroutine is identical to Listing 6.10 with one important change. The subroutine:
Begins by echoing the value of the subroutines single argument, strNameSpace.
The variable strNameSpace identifies the namespace used in the connection string each time the subroutine is called. The first time the subroutine is called, strNameSpace is equal to "root".
Uses the VBScript GetObject function to connect to the namespace identified by the subroutines strNameSpace argument.
After establishing a connection to the WMI service and namespace on the target computer, the subroutine retrieves all namespace instances immediately beneath the namespace referenced by strNameSpace.
Using a For Each loop, the subroutine enumerates the namespace instances immediately beneath the currently connected namespace. However, instead of the script simply echoing the names of the child (or sub) namespaces, each child (or sub) namespace name is concatenated with the current namespace name. This name is then passed to a new invocation of the EnumNameSpaces subroutine.
Substeps a through d are repeated until all namespace instances are enumerated.
Listing 6.11 Retrieving All CIM Namespaces
1 2 3 4 5 6 7 8 9 10 11 12
The following is output generated from running the script on a Windows 2000 Advanced Server computer:
root root\DEFAULT root\SECURITY root\CIMV2 root\CIMV2\Applications root\CIMV2\Applications\MicrosoftIE root\CIMV2\ms_409 root\WMI root\directory root\directory\LDAP root\directory\LDAP\ms_409 root\MicrosoftNLB root\MicrosoftNLB\ms_409