Previous Page
Next Page

Accepting Defaults

Several fields are optional in constructing a finely tuned WMI moniker, and there are clearly defined defaults for those optional fields. The defaults are stored in the following registry location: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM\Scripting. There are two keys: impersonation level and default namespace. Impersonation level is set to a default of 3, which means that WMI impersonates the logged-on user. The default namespace is set to root\cimv2. In reality, these are pretty good defaults. The default computer is the local machine, so you don't need to specify the computer name when you're simply running against the local machine. All this means is that a simple connection string to WMI, using the default moniker, would just be "winmgmts:\\". When using the GetObject method, you can use the default connection string as follows:

Set objWMIService = GetObject("winmgmts:\\")

By using a default moniker and omitting the header information, you come up with a rather lean script. You can shorten it even further, as you'll learn in a bit. The SmallBIOS.vbs script that follows is a shorter script than the DetermineBIOS.vbs script, which is included on the companion CD-ROM. (The header information of SmallBIOS.vbs is omitted.)

SmallBIOS.vbs

wmiQuery = "Select * from Win32_BIOS"

Set objWMIService = GetObject("winmgmts:\\")
Set colItems = objWMIService.ExecQuery(wmiQuery)

For Each objItem in colItems
  strBIOSVersion = Join(objItem.BIOSVersion, ",")
  WScript.Echo "BIOSVersion: " & strBIOSVersion
  WScript.Echo ": " & objItem.caption
  WScript.Echo ": " & objItem.releaseDate
Next

Reference Information

The Reference information section of the script comprises three lines. Two of the lines are the same as in many other WMI scripts; the first line in the Reference information section changes depending upon what query you want to run. For the script to return information about the basic input/output system (BIOS) on the server, you need to connect to the Win32_BIOS namespace. Your WMI query does nothing fancyit simply tells WMI that you want to select everything contained in the Win32_BIOS namespace. The actual query looks like the following:

wmiQuery = "Select * from Win32_BIOS"

The two standard lines in the Reference section are the connection to WMI that uses the GetObject method and the moniker. The short version of the moniker follows:

Set objWMIService = GetObject("winmgmts:\\")

Once you have the connection into WMI, you can begin to perform tasks with it. In this case, you want to issue a query and hold the results of that query in a variable called colItems. So you use the following line:

Set colItems = objWMIService.ExecQuery(wmiQuery)

By removing the actual WMI query from the ExecQuery string, you won't need to edit this line of the script when you wish to make a change to your WMI query. The same is true for the WMI connection stringas long as you are running the script on your local machine and working in the root\cimv2 namespace, you don't need to modify that line either when you wish to target a different computer. Now you can see why in our earlier WMI scripts we specified the computer by using strComputer it gave us the ability to modify the value of that variable without having to change the rest of the script.

Worker and Output Information

The Worker and Output information section of the script is used to iterate through the collection that is returned by wmiQuery. After that information is loaded into the collection of items (colItems), you use a For Each...Next construction to walk through the collection and return the desired information. The code for this section of script follows:

For Each objItem in colItems
  strBIOSVersion = Join(objItem.BIOSVersion, ",")
  WScript.Echo "BIOSVersion: " & strBIOSVersion
  WScript.Echo ": " & objItem.caption
  WScript.Echo ": " & objItem.releaseDate
Next

Each item in the collection is assigned to the variable objItem. In this particular situation, only one BIOS can be queried from Win32_BIOS; the nature of WMI is to return single items as a collection. Display the requested information by using the For Each...Next construction. Only one item is in the collection and only one loop is made.

Working with Multivalue Properties

Most of the items in the Output information section are obvious to readers at this point. You use WScript.Echo to output specific values. The first item, strBIOSVersion, is unique because you use the Microsoft Visual Basic, Scripting Edition (VBScript) Join method to turn an array into a string so you can use WScript.Echo to echo out the information. If you tried to use WScript.Echo to directly print out the property, you would get a type mismatch error. (We talk about the Join method later, so for now, let's think of a Join as a "black box tool.") This Join is necessary because the data contained in the BIOSVersion property is stored as an array. Recall from earlier chapters that you can think of an array as multiple cells in a spreadsheet, each of which can contain a certain amount of data. The BIOSVersion property of Win32_BIOS contains several fields of information, but you can't simply use WScript.Echo objItem.BIOSVersion because WScript won't know which field you want returned and, consequently, the command will fail. As you learned in your previous study of arrays, you could use something like objItem.BIOSVersion(0), and if you knew which field in the array contained the most salient information, this would be a valid approach. Short of running the script multiple times and changing the array value an arbitrary number of times, you need to take a better approach.

Note

For more information about arrays, refer to Chapter 4, "Working with Arrays."


One nice way to deal with the multivalue property problem is to use the Join function demonstrated in our earlier script. Let's see how that works. First you need to use a new variable that will hold the result of your Join statement:

strBIOSVersion = Join(objItem.BIOSVersion, ",")

The Join function should be old hat to readers who are familiar with Transact-SQL (T-SQL). An executed Join takes two arguments. It's saying, "I want to join the first thing with the second thing." This is actually quite sophisticated. In the preceding Join statement, you join each field from BIOSVersion with a comma. You assign the result of the operation to the variable strBIOSVersion, and you're ready to echo it out in the next line of your script. Keep in mind that the default query language into WMI is WMI Query Language (WQL). WQL is pronounced "weequil" and SQL (Structured Query Language) is pronounced "seaquil"they not only sound alike but are alike in that many of the tasks you can perform in SQL can also be accomplished in WQL. The Join technique is very important, and you'll use it again when you come across other arrayed properties. Wondering how I knew that BIOSVersion was an array? The Platform SDK told me.

Important

If you try to print out a data value that is stored as an array, you will receive a message stating: "Microsoft VBScript runtime error: type mismatch." You can avoid this error by using the ISArray function.


Detecting array properties

1.
Open the \My Documents\Microsoft Press\VBScriptSBS\Templates\WMITemplate.vbs script in Microsoft Notepad or some other script editor and save it as YourNameIsArray.vbs.

2.
Turn off the On Error Resume Next command by remarking out the line.

'On Error Resume Next

3.
Modify the wmiQuery line so you are choosing everything from the WIN32_ComputerSystem class. This is seen below.

wmiQuery = "Select * from win32_ComputerSystem"

4.
Inside the For Each...Next loop, print out the values for the following properties: Name, Manufacturer, Model, TotalPhysicalMemory, and Username. To do this, edit the WScript.Echo lines currently in the loop. This is seen below.

WScript.Echo "name: " & objItem.name
WScript.Echo "Manufacturer: " & objItem.Manufacturer
WScript.Echo "model: " & objItem.model
WScript.Echo "totalPhysicalMemory: " & objItem.totalPhysicalMemory
WScript.Echo "username: " & objItem.username

5.
Save and run your script. It should print out something similar to the output listed below if it is run in CScript. If it does not, compare your script to \My Documents\Microsoft Press\VBScriptSBS\ch09\IsArray.vbs. Your code must be error free prior to going to the next step.

name: MREDLAPTOP
Manufacturer: TOSHIBA
model: TECRA M3
totalPhysicalMemory: 2146680832
username: NWTRADERS\iammred

6.
Add an additional WScript.Echo command in your For Each...Next loop. You can easily do this by copying one of the existing Echo lines and editing both the property name and the associated string message. Modify the line to use the SystemStartupOptions property, as seen below:

WScript.Echo "SystemStartupOptions: " & objItem.SystemStartupOptions

7.
Save and run the script. You will notice it errors out on the line you just added. The error received is listed below:

Microsoft VBScript runtime error: Type mismatch

8.
The easiest way to fix it is to add the Join function to the line of code, as seen below:

WScript.Echo "SystemStartupOptions: " & join(objItem.SystemStartupOptions)

9.
Add join to the line above the SystemStartupOptions line so that you are trying to join the Username property, as seen below:

WScript.Echo "username: " & join(objItem.username)

10.
Save and run the script. You will see it also produces an error:

Microsoft VBScript runtime error: Type mismatch: 'join'

11.
It is therefore impossible to simply try to join everything together. In trying to solve one error, we run into another. Use the isArray function to determine if the property is an array and then use the appropriate line of code. Delete join from the objItem.UserName line of code. Save and run your script. There should be no errors.

12.
Add a new line above the SystemStartUpOptions line of code. Use the isArray function to determine if the property is an array. Encase the code in an If...Then...End If loop, as seen below:

If IsArray(objItem.SystemStartUpOptions) Then
End If

13.
Add an Else clause that prints out the property without using a Join function, as seen below:

Else
   WScript.Echo "SystemStartupOptions: " & objItem.SystemStartupOptions

14.
It is possible that you have multiple startup options specified for your server or workstation in the Boot.ini file. To present a nicer listing from the script, let's add the second parameter for the Join function, which is the character to use as a line separator. Here we will use a new line, as seen below:

WScript.Echo "SystemStartupOptions: " & join(objItem.SystemStartupOptions, _
        VbCrLf)

15.
Save and run the script. If there are problems, compare it to IsArray.vbs.

Best Practices

In the next procedure, we will illustrate an alternate way to connect to WMI. This can be useful for short, quick scripts. I do not recommend leaving out Option Explicit, not declaring variables, or using convuluted monikers as a general course. As they can be difficult to read, hard to modify, and impossible to troubleshoot.

Alternate ways to connect to WMI

1.
Open \My Documents\Microsoft Press\VBScriptSBS\Templates\BlankTemplate.vbs in Notepad or your favorite script editor. Save the file as YourNameAlternateWMI.vbs.

2.
On the first line, use Set to assign the object that comes back from GetObject to a variable named colItems. Use the ExecQuery method to select everything from the WIN32_LogicalDisk class. This can be on a single line. (The line below is wrapped due to publishing style constraints. If you type it on a single line, remove the _ when you put it together.)

Set colItems = GetObject("winmgmts:\\").ExecQuery _
   ("Select * from win32_logicaldisk")

3.
To investigate the type of object that is returned by the command, use the TypeName function and print out the name of the object contained in the colItems variable, as seen below.

WScript.Echo "colitems is: " & TypeName(colItems)

4.
Save and run the script. You will notice it reports colItems is an SWbemObjectSet object.

5.
On a new line, use For Each...Next to walk through the collection of objects returned in the first line of the script. Use the variable obj to singularize an item from the collection. Print out the name property from the WIN32_LogicalDisk class. This is seen below:

For Each obj In colItems
         WScript.Echo "Drive name: " & obj.name
Next

6.
On the next line, use the Get method from SWbemServices to connect to a specific drive, drive C. To do this, you must identify the key value of the WMI class and supply a value for the key that represents an individual instance of the class. The WMI object browser can be used to find the key property, as seen in Figure 9-1. Use objItem to hold the object that is returned.

Set objItem = GetObject("winmgmts:\\").get _
   ("win32_logicaldisk.deviceID='c:'")

Figure 9-1. The WMI object browser provides an easy way to identify key properties


7.
Use the TypeName function and echo out the name of the object contained in the objItem variable. This is seen below:

WScript.Echo "objItem is: " & TypeName(objItem)

8.
Save and run the script. You will notice objItem is reported as sWbemObjectEx.

9.
Use WScript.Echo to print out the size of the C drive. This is seen below.

WScript.Echo "Size of drive " & objItem.size

10.
Save and run the script. If it does not perform as expected, compare your script with AlternateWMI.vbs in the Chapter 9 folder.

Quick Check

Q.

Why do you need a moniker for WMI?

A.

The WMI moniker gives you the ability to easily connect to WMI.

Q.

What construction is required to return property data stored in an array?

A.

You need to either specify the element you're interested in, or simply use the Join function to give you a string to work with.

Q.

What part of the WMI moniker is required?

A.

The required part of the WMI moniker is the prefix WinMgmts:.

Q.

What are the two optional parts of the WMI moniker?

A.

The two optional parts of the WMI moniker are the security settings and the WMI object path.



Previous Page
Next Page