• No results found

In this lab, you modify the script from Lab 16 so that it echoes out the time zone con- figured on the computer.

Lab Instructions

1. Open Notepad.exe.

2. Open Lab16Solution.vbs, and save it as lab17.vbs.

3. Edit the wmiQuery so that it points to Win32_TimeZone. The code will look like the following:

wmiQuery = “Select * from Win32_TimeZone”

4. Inside the For Each objItem In colItems loop, delete all but one of the

WScript.Echo statements so that the code looks like the following:

For Each objItem In colItems

WScript.Echo “Caption: “ & objItem.Caption Next

5. Save and run the file. You are now pointing to the Caption field of

9

WMI Continued

In this chapter, you’ll continue working with WMI. You’ll build upon the concepts learned in Chapter 8, “Why Windows Management Instrumentation?” and see different ways to leverage your investment in WMI to assist in day-to-day network administrative tasks.

Before You Begin

To work through the material presented in this chapter, you need to be familiar with the following concepts from earlier chapters:

■ Connecting to the default WMI namespace

■ Accessing properties of dynamic WMI classes

■ Implementing the For...Next construction

■ Implementing a WMI query

After completing this chapter you will be familiar with the following: ■ Alternative ways of configuring the WMI moniker

■ Querying WMI

■ Setting impersonation levels

■ Defining the WMI object path

■ Navigating the WMI namespace

Alternate Ways of Configuring the WMI Moniker

In this section, you are going to look at different ways of constructing the WMI moni­ ker string. There are essentially three parts to the moniker. Of the three parts, only one is mandatory. These parts are listed here:

■ The prefix WinMgmts: (This is the mandatory part.)

■ A security settings component

■ A WMI object path component

Just the Steps

To construct the moniker

1. Use the prefix WinMgmts:.

2. Define the security settings component, if desired. 3. Specify the WMI object path component, if desired.

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 you can simplify your connection string to WMI. A 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 still shorten it even more, as you’ll learn in a bit, but 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 Small- BIOS.vbs is omitted.)

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 would be consistent among many WMI scripts; the first line in the Reference informa­ tion section would change depending upon what query you wanted to run. For the

script to return information about the BIOS on the server, you need to connect to the

Win32_BIOS namespace. Your WMI query does nothing fancy—it 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 contents of the WMI query from the line that uses the ExecQuery

method, you won’t normally need to change this line of the script. The same is true for the WMI connection string—as 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. 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 collec­ tion of items (colItems), you use a For Each...Next construction to walk through the col­ lection 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 situa­ tion, only one BIOS can be queried from Win32_BIOS; however, 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, so you make only one

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. However, the first item, strBIOS-

Version, is unique because you use the VBScript Join method to echo out the informa­

tion. (We talk about the Join method in two paragraphs, so for now, let’s think of a Join

as a “black box tool.”) This Join is necessary because the data contained in the BIOS-

Version 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 do a WScript.Echo objItem.BIOSVersion because

WScript won’t know which field you want returned and, consequently, the command

would fail. As you learned in your previous discussion of arrays, you could use some- thing like objItem.BIOSVersion(0), and if you knew which field in the array contained the most salient information, this would be a valid approach. However, short of run­ ning the script multiple times and changing the array value an arbitrary number of times, you need to take a better approach.

See Also For more information about arrays, refer to Chapter 4, “The Power of Many.”

One cool way to deal with the multivalue property problem is to use the Join tech­ nique 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 statement should be old hat to readers who are familiar with T-SQL. An exe­ cuted Join takes two arguments. It’s saying, “I want to join the first thing with the sec­ ond 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 WQL. Now WQL is pronounced “weequil” and SQL 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 accom­ plished 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.

Quick Check

Q. Why do you need a moniker for WMI?

A. The WMI moniker gives you the ability to connect to WMI in an easier fashion.

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 a Join

function with a comma 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 to the WMI moniker?

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

Moniker Security Settings

In many cases, the default security settings work just fine for the WMI moniker. In many example scripts, you will see the line impersonationLevel=impersonate in a script. This line is often not needed, because the default security setting for Microsoft Windows 2000, Windows XP, and Windows Server 2003 is set to the impersonation level to be equal to impersonate.

Note When I first started using WMI in my scripting, I noticed lots of scripts had imperson­

ationLevel=impersonate set, and it made me curious. After a lot of searching I found the other

levels. However, when I tried to change the security settings, the script failed. The reason? You cannot specify security settings when running local. They work only when you are connect0 ing remotely to another computer.

But what does that really mean? Why are there options we would not normally utilize? You can use four levels of impersonation: Anonymous, Identify, Impersonate, and Del­ egate. By default, WMI uses the Impersonate permission, which allows a WMI call to utilize the credentials of the caller. When the person calling the WMI script is a domain administrator, the script runs with domain administrator privileges. You can also use other impersonation levels, as described in Table 9-1.

Table 9-1 Impersonation Levels

Moniker Meaning Registry value

Anonymous Hides the credentials of the caller. Calls to WMI might fail with this impersonation level.

Identify Allows objects to query the credentials of the caller. Calls to WMI might fail with this impersonation level.

Impersonate Allows objects to use the credentials of the caller. This is the recommended impersonation level for Scripting API for WMI calls.

Delegate Allows objects to permit other objects to use the creden­ tials of the caller. This impersonation will work with Script­ ing API for WMI calls but might constitute an unnecessary security risk.

1 2 3

4

If you decide to specify the impersonation level of the script, the code would look like the following:

Set objWMIService=GetObject(“winmgmts:{impersonationLevel=impersonate}”)

Because Impersonate is the default impersonation level for WMI, the addition of the curly braces and impersonationLevel=impersonate code is redundant. If you want to keep your moniker nice and clean, and yet you feel the need to modify the imperson­ ation level, you can do this easily by defining the impersonation level of the SWbem-

Security object. In practice, your code might look like the following:

Set objWMIService=GetObject(“winmgmts:\\” & strComputer & wmiNS) objWMIService.Security_.ImpersonationLevel = 4

In this code, the first line contains the normal moniker to make the connection to WMI. You use strComputer and wmiNS to specify target computers and the target namespace, respectively. Because you haven’t specified an impersonation level, you’re using the default Impersonate security setting. On the next line, you use the handle that came back from the GetObject command that was assigned to objWMIService, and you define the

impersonationLevel to be equal to 4. (Impersonation values are listed in Table 9-1.) Obvi­

ously, you could define a constant and set it to a value of 4 and then substitute the con­ stant value for 4 in the script. ImpersonationLevel is a property of Security_. Security_ is a property of the SWbemSecurity object. The SWbemSecurity object is used to read or set security settings for other WMI objects such as SWbemServices, which is actually the object created when you use GetObject and the WMI moniker. Understanding this “gob­ bledygook” is not necessary for writing WMI scripts; however, having a feel for some of it is useful if you’re going to do much reading in the Platform SDK for WMI.

WbemPrivilege Has Its Privileges

To add elevated privileges, you need to add a privilege string in the space immediately following the impersonation level. These privilege strings correspond to the Wbem-

PrivilegeEnum constants, which are documented in the Platform SDK. Some of the

more useful privilege strings for network administrators are listed in Table 9-2. (There are 26 defined privileges in the Platform SDK, most of which are of interest only to developers writing low-level WMI applications.)

Table 9-2 Privilege Strings

Privilege Value Meaning

SeCreateTokenPrivilege 1 Required to create a primary token.

SeLockMemoryPrivilege 3 Required to lock physical pages in memory. SeMachineAccountPrivilege 5 Required to create a computer account.

SeSecurityPrivilege 7 Required to perform a number of security-related

functions, such as controlling and viewing audit mes­ sages. This privilege identifies its holder as a security operator.

SeTakeOwnershipPrivilege 8 Required to take ownership of an object without

being granted discretionary access. This privilege allows the owner value to be set only to those values that the holder might legitimately assign as the owner of an object.

SeSystemtimePrivilege 11 Required to modify the system time. SeCreatePagefilePrivilege 14 Required to create a paging file. SeShutdownPrivilege 18 Required to shut down a local system.

SeRemoteShutdownPrivilege 23 Required to shut down a system using a network request.

SeEnableDelegationPrivilege 26 Required to enable computer and user accounts to be trusted for delegation.

As you can see from Table 9-2, some of these privileges are rather interesting. This being the case, how do you request them? Well, this is where your work gets a little interesting. If you’re requesting the privilege in a moniker string, you use the privilege string listed in Table 9-2, but you have to drop the Se part and the Privilege part of the string. For example, if you want to request the SeShutdownPrivilege in a moniker, you would specify the privilege as Shutdown, as illustrated in the following WMI connec­ tion string:

Summary

In this chapter, you examined the construction of the WMI moniker. You looked at var­ ious ways in which the moniker can be built and the ways in which it can be utilized. In addition, you studied the defaults that are configured on a Windows Server 2003 machine, and saw different ways of modifying that behavior. You then spent quite a bit of time looking at security surrounding the WMI connection. You looked at both impersonation features and individual security settings. Finally, the chapter concluded with a discussion of WbemPrivilegeEnum constants and an exploration of how to con­ vert WbemPrivilegeEnum constants into Windows NT and Windows 2000 strings.

Quiz Yourself

Q. What is the WMI moniker, and why should you care?

A. The WMI moniker is used to simplify the connection into WMI. It includes both default security and default namespace configuration information to the amount of scripting involved.

Q. What are impersonation levels?

A. Impersonation levels control allowed privileges when connecting to a remote WMI namespace.

Q. What are the four impersonation levels available to WMI?

A. The four impersonation levels available to WMI are Anonymous, Identify, Impersonate, and Delegate.

Q. In Windows Server 2003, what is the default impersonation level?

A. In Windows Server 2003, the default impersonation level is Impersonate.

Q. How do you use a WbemPrivilegeEnum privilege constant in constructing the WMI moniker?

A. To use the WbemPrivilegeEnum privilege constant in constructing a WMI moniker, you drop the initial Se and the trailing privilege parts of the constant. For example, if you want to have the SeRemoteShutdownPrivilege when connecting to a remote WMI namespace, you would simply use the RemoteShutdown portion of the privilege name in your moniker, like this: impersonationLevel= RemoteShutdown.

On Your Own

Lab 18a Using the Default WMI Moniker

In this lab, you will practice using the default WMI moniker. To do this, you write a cute little script that enumerates all the programs listed in the Add/Remove Programs dialog box, available from Control Panel.

Lab Instructions

1. Open Notepad.exe.

2. On the first line, type Option Explicit to ensure you declare all variables used in the script.

3. Declare the following variables: objWMIService, colItems, and objItem. Add com­ ments following each declaration to specify what each variable is used for.

4. Set objWMIService equal to what comes back from the GetObject method when

used in conjunction with the WMI moniker. Your code will look like the following: Set objWMIService = GetObject(“winmgmts:\\”)

5. Set colItems equal to what comes back from issuing the WQL statement “Select *

from AddRemovePrograms” as you use the execQuery method. Your code will

look like the following:

Set colItems = objWMIService.ExecQuery(“SELECT * FROM AddRemovePrograms”)

6. Use a For Each...Next loop to iterate through colItems as you look for the follow­ ing properties of the AddRemovePrograms object: displayName, Publisher and

Version. Use the variable objItem to assist you in iterating through the collection.

Make sure you close out the For Each...Next loop with the Next command. Your code could will look like the following:

For Each objItem In colItems

WScript.Echo “DisplayName: “ & objItem.DisplayName WScript.Echo “Publisher: “ & objItem.Publisher WScript.Echo “Version: “ & objItem.Version WScript.Echo

Next

7. Save your file as Solution18-1.vbs.

8. Make sure you run this program in CScript by going to a command prompt and typing cscript pathtoyourfile\solution18-1.vbs. (More than likely, you have a lot of programs in Add/Remove Programs. If you run the program by double-