Programming4us
         
 
 
Windows

Scripting Windows 7 with WSH : Programming the Windows Management Instrumentation Service

5/3/2011 11:35:46 AM
Windows Management Instrumentation (WMI) is a powerful tool that gives you access to just about every aspect of Windows Home Server and of remote computers. With WMI, your scripts can manage applications, systems, devices, networks, and much more. WMI consists of a series of classes that implement various properties and methods that you can access using your scripts. For example, the Win32_OperatingSystem class represents the computer’s operating system. Its properties include InstallDate, the date and time the OS was installed, and LastBootUpTime, the date and time when the OS was last started; its methods include Reboot for restarting the computer and SetDateTime for setting the system’s date and time.

Note

WMI is massive. It has hundreds of classes that you can use, although you’ll mostly use the Win32 classes, which enable you to manage the operating system, hardware, and applications, and to monitor performance. For the complete WMI reference, see http://msdn.microsoft.com/en-us/library/aa394582.aspx.


Referencing the WMI Service Object

Your WMI scripts will always begin by setting up a variable for the WMI service object. One way to do that is to create the SWbemLocator object and use it to connect to the WMI service. Here’s the code:

strComputer = "localhost"
Set objLocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMI = objLocator.ConnectServer(strComputer, "root\cimv2")
objWMI.Security.ImpersonationLevel = 3

That works fine, but most scripts use a shortcut method that reduces to just a couple of statements:

strComputer = "localhost"
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\cimv2")

Tip

I like to use localhost to reference the local computer because it’s straightforward and easy to read. However, you can also use just dot (.) to refer to the local machine:

strComputer = "."
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\cimv2")


Returning Class Instances

After you have your WMI service object, you can use it to access a class. Each class is really a collection of instances, or actual implementations of the class. For example, the Win32_UserAccount class consists of all the user accounts defined on the computer. Each user account is an instance of the Win32_UserAccount class. To access the instances of a class, you can use either of the following WMI object methods: ExecQuery or InstancesOf.

The ExecQuery method executes a SELECT query using the WMI Query Language (WQL). In general, this method uses the following form:

object.ExecQuery("SELECT * FROM class")

objectA variable that references the WMI object.
classThe WMI class you want to work with.

For example, the following method assumes the WMI object is referenced by the objWMI variable, and the query returns all the instances of the Win32_UserAccount class:

objWMI.ExecQuery("SELECT * FROM Win32_UserAccount")

The InstancesOf method uses the following syntax:

object.InstancesOf("class")

objectA variable that references the WMI object.
classThe WMI class you want to work with.

For example, the following method assumes the WMI object is referenced by the objWMI variable, and the code returns all the instances of the Win32_UserAccount class:

objWMI.InstancesOf("Win32_UserAccount")

Which method should you use? If you want to work with all instances of a particular class, either method is fine, and you may gravitate to the InstancesOf method only because it’s slightly shorter. However, if you want to work with only a subset of the instances, the ExecQuery method is better because you can add a WHERE clause to the WQL statement. For example, if you just want to work with the account named Administrator, the following code returns just that instance from the Win32_UserAccounts class:

objWMI.ExecQuery("SELECT * FROM Win32_UserAccount " & _
"WHERE Name = 'Administrator'")

Both ExecQuery and InstancesOf return a collection object that contains the class instances. You usually store that collection in a variable, as in this example:

Set objUsers = objWMI.ExecQuery("SELECT * FROM Win32_UserAccount")

You could then use a For Each...Next loop to run through the collection and perform some action on each instance. For example, Listing 1 presents a script that runs through all the instances of the Win32_UserAccount class, stores the Name and Fullname properties for each user in a string, and then displays the string.

Listing 1. Script That Runs Through the Instances of the Win32_UserAccount Class
Option Explicit
Dim strComputer, strUserInfo
Dim objWMI, objUsers, objUser
'
' Work with the local computer
'
strComputer = "localhost"
'
' Get the WMI service
'
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\cimv2")
'
' Store the instances of the Win32_UserAccount class
'
Set objUsers = objWMI.ExecQuery("SELECT * FROM Win32_UserAccount")
'
' Initialize the display string
'
strUserInfo = ""
'
' Loop through the instances
'
For each objUser in objUsers
strUserInfo = strUserInfo & objUser.Name & " (" & _
objUser.FullName & ")" & vbCrLf
Next
'
' Display the string
'
WScript.Echo strUserInfo
'
' Release the objects
'
Set objWMI = Nothing
Set objUsers = Nothing
Set objUsers = Nothing


In many cases, the class only returns a single instance, either because the class only has one instance or because you used the WQL WHERE clause to restrict the class to a particular instance. Either way, you still need to use a For Each...Next loop to extract the data from the instance.

As an example, consider the script in Listing 2.

Listing 2. Script That Displays BIOS Data
Option Explicit
Dim strComputer, strBIOS
Dim objWMI, objBIOS, objItem
'
' Get the WMI service
'
strComputer = "mediapcrver"
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\cimv2")
'
' Get the BIOS instance
'
Set objBIOS = objWMI.ExecQuery("SELECT * FROM Win32_BIOS " & _
"WHERE PrimaryBIOS = true")
'
' Initialize the display string
'
strBIOS = "BIOS Data for " & UCase(strComputer) & ":" & vbCrLf & vbCrLf
'
' Collect the BIOS data
'
For Each objItem in objBIOS
strBIOS = strBIOS & _
"BIOS Name:" & vbTab & objItem.Name & vbCrLf & _
"Manufacturer:" & vbTab & objItem.Manufacturer & vbCrLf & _
"BIOS Version:" & vbTab & objItem.Version & vbCrLf & _
"SMBIOS Version:" & vbTab & objItem.SMBIOSBIOSVersion & vbCrLf & _
"BIOS Date:" & vbTab & ConvertToDate(objItem.ReleaseDate)

Next
'
' Display the string
'
WScript.Echo strBIOS
'
' Release the objects
'
Set objWMI = Nothing
Set objBIOS = Nothing
Set objItem = Nothing
'
' This function takes a datetime string and
' converts it to a real date object
'
Function ConvertToDate(strDate)
Dim strYear, strMonth, strDay
strYear = Left(strDate, 4)
strMonth = Mid(strDate, 5, 2)
strDay = Mid(strDate, 7, 2)
ConvertToDate = DateSerial(strYear, strMonth, strDay)
End Function


This script uses ExecQuery to return the instance of the Win32_BIOS class that represents the computer’s primary BIOS (that is, where the PrimaryBIOS property equals true). Then a For Each...Next loop runs through the single instance and uses a string variable to store the values of five properties: Name, Manufacturer, Version, SMBBIOSBIOSVersion, and ReleaseDate. The last of these is converted to a proper date object using the ConvertToDate function. The script then uses the Echo method to display the results, as shown in Figure 1.

Figure 1. A computer’s BIOS data displayed by the script in Listing 30.12.


Scripting a Remote Computer

In the WMI examples you’ve seen so far, I’ve used localhost as the value of the strComputer variable, which connects to the local computer’s WMI service:

strComputer = "localhost"
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\cimv2")

You may have noticed that in Listing 30.11, I did something a bit different:

strComputer = "mediapc"
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\cimv2")

In this case, I used the name of the local computer—mediapc—instead of localhost. However, WMI scripting doesn’t restrict you to working only with the local machine. In fact, WMI was created so that IT types and network admins could manage remote computers on the network. This means that it’s almost trivial to configure a script to run on a network client:

  • You change the value of the strComputer variable to the name of the remote computer you want to manage.

  • You configure the network client’s firewall to accept remote administration traffic.

Note

Unfortunately, scripting remote Windows Vista and Windows 7 computers only works if those PCs have User Account Control turned off. When UAC is activated on a remote computer, your script will always generate “Access Denied” errors (even if you run the script under the Administrator account). Because UAC is such an important part of the Windows 7 and Windows Vista security models, turning UAC off just to access remote machines in scripts isn’t worth it.


Listing 3 shows a script that returns disk drive information from a remote computer.

Listing 3. Script That Displays Disk Drive Data for a Remote Computer on the Network
Option Explicit
Dim strComputer, strDriveData
Dim objWMI, objDrives, objDrive
'
' Get the WMI service
'
strComputer = "officepc"
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\cimv2")
'
' Get the instances of hard disk drives (MediaType = 12)
'
Set objDrives = objWMI.ExecQuery("SELECT * FROM Win32_LogicalDisk " & _
"WHERE MediaType = 12")
'
' Initialize the display string
'
strDriveData = "Disk Drive Data for " & UCase(strComputer) & ":" & vbCrLf & vbCrLf
strDriveData = strDriveData & _
"Letter:" & vbTab & _
"Name:" & vbTab & _
"System:" & vbTab & _
"Size:" & vbTab & _
"Free:" & vbTab & _
"% Free:" & vbTab & vbCrLf & _
"=====" & vbTab & _
"=====" & vbTab & _
"=====" & vbTab & _
"=====" & vbTab & _
"=====" & vbTab & _
"=====" & vbTab & vbCrLf
'
' Collect the drive data
'
For Each objDrive In objDrives
strDriveData = strDriveData & _
objDrive.Name & vbTab & _
objDrive.VolumeName & vbTab & _
objDrive.FileSystem & vbTab & _
FormatNumber(objDrive.Size / 1073741824, 1) & " GB" & vbTab & _
FormatNumber(objDrive.FreeSpace / 1073741824, 1) & " GB" & vbTab & _
FormatPercent(objDrive.FreeSpace / objDrive.Size, 1) & vbTab & vbCrLf

Next
'
' Display the string
'
WScript.Echo strDriveData
'
' Release the objects
'
Set objWMI = Nothing
Set objDrives = Nothing
Set objDrive = Nothing


The script begins by setting the strComputer variable to officepc, which is the name of the client computer on my network. The script then gets the remote computer’s WMI service and uses it to return the instances of the remote computer’s Win32LogicalDisk class, which represents a computer’s logical disk drives. In this case, I’m only interested in the hard drives, so I use the WHERE clause to return only those disks where the MediaType property equals 12.

Note

If you want to examine a computer’s removable media drives (except its floppy drives), use WHERE MediaType = 11. Floppy drives use various values for the MediaType property, depending on the floppy format (3.5 inch versus 5.25 inch), the size (for example, 1.2MB or 1.44MB), and the number of bytes per sector (for example, 512 or 1024).


The script initializes the strDriveData display variable, and then it uses For Each...Next to loop through the hard drive instances. In each case, six values are added to the strDriveData string: the Name (drive letter), VolumeName, FileSystem, Size, and FreeSpace properties, and a calculation of the percentage of free space available. The strDriveData string is then displayed using the Echo method. Figure 2 shows an example.

Figure 2. A remote computer’s disk drive data displayed by the script in Listing 2.

Other -----------------
- Scripting Windows 7 with WSH : Scripting Internet Explorer
- Scripting Windows 7 with WSH : Programming the WshNetwork Object
- Scripting Windows 7 with WSH : Programming the WshShell Object (part 2)
- Scripting Windows 7 with WSH : Programming the WshShell Object (part 1)
- Scripting Windows 7 with WSH : Programming the WScript Object
- Scripting Windows 7 with WSH : Programming Objects
- Scripting Windows 7 with WSH : Scripts and Script Execution
- Adding Macs to Your Windows 7 Network : Letting Windows Computers See Your Mac Shares
- Adding Macs to Your Windows 7 Network : Using a Mac to Make a Remote Desktop Connection to Windows 7
- Adding Macs to Your Windows 7 Network : Connecting to a Windows Shared Folder
- Adding Macs to Your Windows 7 Network : Connecting to the Windows Network
- Windows 7 : Controlling and Customizing Your Website (part 5) - Viewing the Server Logs
- Windows 7 : Controlling and Customizing Your Website (part 4) - Disabling Anonymous Access
- Windows 7 : Controlling and Customizing Your Website (part 3) - Working Without a Default Document
- Windows 7 : Controlling and Customizing Your Website (part 2) - Setting the Website’s Default Document
- Windows 7 : Controlling and Customizing Your Website (part 1)
- Windows 7 : Adding Folders and Files to the Default Website (part 3) - Adding a Folder to the Default Website
- Windows 7 : Adding Folders and Files to the Default Website (part 2) - Changing the Default Website Home Page
- Windows 7 : Adding Folders and Files to the Default Website (part 1) - Setting Permissions on the Default Website Folder
- Turning Windows 7 into a Web Server : Understanding the Default Website
 
 
Most View
- SQL Azure : Combining Patterns
- User-Level Security : Authorization and Impersonation (part 2) - Claims-Based Authorization
- Exchange Server 2010 : Manage Web-Based Email Access (part 1) - Configure OWA URLs
- Sharepoint 2010 : Excel Service - Demonstration Scenario (part 2)
- SharePoint 2010 : Configure Access Requests for Lists and Libraries
- The Exchange Server 2010 Deployment Process
- Windows Phone 7: Finding a Contact
- Exchange Server 2007 : Manage Resource Mailboxes
- Windows Server 2003 : Configuring IAS for Use with VLANs
- Mapping Local Logins to Logins on Linked Servers
Top 10
- Implementing Edge Services for an Exchange Server 2007 Environment : Utilizing the Basic Sender and Recipient Connection Filters (part 3) - Configuring Recipient Filtering
- Implementing Edge Services for an Exchange Server 2007 Environment : Utilizing the Basic Sender and Recipient Connection Filters (part 2)
- Implementing Edge Services for an Exchange Server 2007 Environment : Utilizing the Basic Sender and Recipient Connection Filters (part 1)
- Implementing Edge Services for an Exchange Server 2007 Environment : Installing and Configuring the Edge Transport Server Components
- What's New in SharePoint 2013 (part 7) - BCS
- What's New in SharePoint 2013 (part 6) - SEARCH
- What's New in SharePoint 2013 (part 6) - WEB CONTENT MANAGEMENT
- What's New in SharePoint 2013 (part 5) - ENTERPRISE CONTENT MANAGEMENT
- What's New in SharePoint 2013 (part 4) - WORKFLOWS
- What's New in SharePoint 2013 (part 3) - REMOTE EVENTS