March 4th, 2009

Hey, Scripting Guy! How Do I Migrate My VBScript WMI Queries to Windows PowerShell?

Hey, Scripting Guy! Question

We are pretty well annoyed at you guys. We spent all this time and energy creating all these VBScripts over the last nine years. We have several hundred VBScripts that we use in production, and with uncertain economic times, you are now telling me I have to rewrite all these scripts in Windows PowerShell? Most of these scripts use WMI, which, if you were honest and would admit it, has a rather convoluted syntax, and I do not relish the idea of going through that again. Some of those queries literally took me more than a week of futzing around to get the thing to work. I would rather get a root canal than go through that again.

– VT

SpacerHey, Scripting Guy! Answer

Hi VT,

You caught me on a rather unusual day. I am drinking coffee this morning. Probably because I was up till nearly midnight planning the editorial calendar to the end of the fiscal year. Anyway, when I drink coffee, it is Peaberry beans I bring back from the island of Hawaii (also known as the Big Island). I grind the beans in my coffee grinder and place them gently into my French press, which allows for the enjoyment of full flavor. I then warm my cream in the microwave for exactly 60 seconds on medium. I heat my coffee mug by filling it with water, and microwaving it on high for 60 seconds. By this time, the freshly drawn spring water has heated in my water kettle that I fell in love with while I was in Paris a few years ago. (That is Paris, France, and not Paris, Kentucky.) I use half a spoon of Turbinado I brought back from Maui, Hawaii, to sweeten my cup of coffee. To me there is just no point in drinking an inferior cup of coffee.

Why the discussion of coffee? Because, VT, it seems to me you need to lay off the caffeine. Next time you go get a cup of Joe, grab the pot with the green handle. I can certainly sympathize with your dilemma, but there are few things in life worth getting too excited about. Repeat after me: “Serenity now.” In this particular case there is absolutely nothing to get upset about. Nothing at all, because VBScript is going to be in Windows 7, and it is also in Windows Server 2008 R2. If you have a perfectly working VBScript that does everything you want it to do, there is absolutely no reason to get rid of it. I do believe you should be learning Windows PowerShell, however, because it is extremely powerful and is central to our management story moving forward. Windows 7 and Windows Server 2008 R2 both have Windows PowerShell 2.0 built in, and there are many easy-to-use cmdlets included in both platforms that will greatly simplify common administrative tasks moving forward. The time to learn Windows PowerShell is when you have time to think about it, not at 2:00 A.M. when the server is down and you are wondering how to remote into it.

I did run across one company in Frankfurt, Germany, last year that had decided to migrate all their existing VBScripts to Windows PowerShell. They only wanted to support a single scripting platform. Pretty cool, but most companies do not have that luxury. But suppose you do decide to migrate your VBScript WMI queries to Windows PowerShell. How would you go about it? I am finished with my perfect cup of coffee, so let’s roll up our sleeves and get to work.

This week we will be looking at working with WMI from within Windows PowerShell. In honor of this week, we have created a new WMI Scripting Hub that pulls together a number of useful articles and tools from all over the Script Center into a single location. Because the articles will be using Windows PowerShell, you may also be interested in the Windows PowerShell Scripting Hub. You will find information there that will tell you how to download and install Windows PowerShell.

The Get-WmiObject cmdlet in Windows PowerShell has the –query parameter. We can use the –query parameter to supply a WMI Query language (WQL) syntax to the get-WmiObject cmdlet. This makes it easy to transfer your investment in complicated WMI queries you may have written for VBScript directly into Windows PowerShell.

Suppose we have the List Printer Drivers script. The ListPrinterDrivers.vbs script is seen here:

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colInstalledPrinters =  objWMIService.ExecQuery _
    ("Select * from Win32_PrinterDriver")

For each objPrinter in colInstalledPrinters
    Wscript.Echo "Configuration File: " & objPrinter.ConfigFile
    Wscript.Echo "Data File: " & objPrinter.DataFile
    Wscript.Echo "Description: " & objPrinter.Description
    Wscript.Echo "Driver Path: " & objPrinter.DriverPath
    Wscript.Echo "File Path: " & objPrinter.FilePath
    Wscript.Echo "Help File: " & objPrinter.HelpFile
    Wscript.Echo "INF Name: " & objPrinter.InfName
    Wscript.Echo "Monitor Name: " & objPrinter.MonitorName
    Wscript.Echo "Name: " & objPrinter.Name
    Wscript.Echo "OEM Url: " & objPrinter.OEMUrl
    Wscript.Echo "Supported Platform: " & objPrinter.SupportedPlatform
    Wscript.Echo "Version: " & objPrinter.Version
Next

The WQL query in the ListPrinterDrivers.vbs script is passed to the ExecQuery method. The query is this string:

Select * from Win32_PrinterDriver

We can use the WQL query directly with Get-WmiObject as seen here:

Get-WmiObject -Query "Select * from Win32_PrinterDriver"

When we run the above command, we are treated to an output that displays the same information that is provided with the ListPrinterDrivers.vbs script. The WQL query was the same, so it stands to reason the same information would be returned from WMI. The results of the command are seen here:

Image of the results of running the above command

 

While everything is currently groovy (I am as a matter of fact listening to Take Five by Dave Brubeck), there is really no reason to use the –query parameter with the Get-WmiObject cmdlet when the query is in the Select everything from the class format as seen here:

Select * from whateverwmiclass

The reason is that the when you use Select * from the class, you can obtain the same information more easily by using the –class parameter and no filter as seen here:

Get-WmiObject –Class Win32_PrinterDriver

Suppose you have a script such as ListDiskFreeSpace.vbs:

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

Set colDisks = objWMIService.ExecQuery _
    ("Select * from Win32_LogicalDisk Where DriveType = 3")

For Each objDisk in colDisks
    Wscript.Echo "DeviceID: "& vbTab &  objDisk.DeviceID       
    Wscript.Echo "Free Disk Space: "& vbTab & objDisk.FreeSpace
Next

The query section in the ListDiskFreeSpace.vbs script can be “stolen” from the ListPrinterDrivers.vbs script and used directly:

Get-WmiObject -Query "Select * from Win32_LogicalDisk Where DriveType = 3"

When we run the script, we are greeted with the information seen here:

Image of the output from the script

 

Now, let’s take a look at something that can be incredibly difficult: the Associators Of query. This script is referenced in this article:

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
 & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colShares = objWMIService.ExecQuery _
 ("ASSOCIATORS OF {Win32_Share.Name='Scripts'} WHERE " _
 & "AssocClass=Win32_ShareToDirectory")
For Each objFolder in colShares
 Wscript.Echo objFolder.Name
Next

The Associators Of query seen in the AssociatorsOfShareToFolder.vbs is shown here:

"ASSOCIATORS OF {Win32_Share.Name='Scripts'} WHERE AssocClass=Win32_ShareToDirectory"

To get the query into the pattern above, we deleted the closing quote and underscore from the first line, and deleted the ampersand and quote from the second line. It will provide the mapping between a shared folder named scripts and the directory name associated with the share. The problem with writing Associators Of queries is they are really finicky in regards to placements of quotation marks, curly brackets, and the like. This is definitely a situation where we want to leverage the development effort already done. Once again, we paste the code into the query parameter (the below code is a single line):

Get-WmiObject -Query "ASSOCIATORS OF {Win32_Share.Name='Scripts'} WHERE`
AssocClass=Win32_ShareToDirectory"

When we run the script, we are cheerfully greeted with the output seen here:

Image of the output of the script

 

That was pretty fun. Let’s try our luck once again and see what happens. Suppose you have a VBScript that you use to retrieve files and their version numbers from a particular folder. You would like to migrate it to Windows PowerShell. Such a script is referenced in this “Hey, Scripting Guy!” article:

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colFileList = objWMIService.ExecQuery _
    ("ASSOCIATORS OF {Win32_Directory.Name='C:\Windows\System32'} Where " _
        & "ResultClass = CIM_DataFile")

For Each objFile In colFileList
    If objFile.Extension = "dll" Then
        Wscript.Echo objFile.Name & " -- " & objFile.Version
    End If
Next

The Associators Of query from the ListFilesAndVersion.vbs script is seen here:

"ASSOCIATORS OF {Win32_Directory.Name='C:\Windows\System32'} Where " _
        & "ResultClass = CIM_DataFile"

Once again, because the Associators Of query was rather long, it was broken into two lines of code. We need to remove the closing quotation mark and underscore from the first line, and the ampersand and opening quotation mark from the second line. The cleaned up query is seen here:

"ASSOCIATORS OF {Win32_Directory.Name='C:\Windows\System32'} Where ResultClass = CIM_DataFile"

We open our Windows PowerShell console, use the Get-WmiObject cmdlet with the –query parameter, and paste the Associators Of query directly into the command line. This is seen here (remember this command has wrapped; it is a single command):

Get-WmiObject -Query "ASSOCIATORS OF {Win32_Directory.Name='C:\Windows\System32'}` 
Where ResultClass = CIM_DataFile"

We are again greeted with success. The output on my computer is seen here:

Image of the output of the script

 

See, VT, there is nothing to get excited about. In fact, I am not sure how to say this other than to just come on out and say it. Using the –query parameter with the Get-WmiObject cmdlet is a heck of a lot better for your mental hygiene than saying “Serenity now!” WMI Week continues to roll on, and we have yet to write a script. Three down and one to go, see you tomorrow for the exciting conclusion of WMI Wweek. Until then, be mellow (Dave Brubeck is now playing “The Duke”; yeah, baby).

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

Author

0 comments

Discussion are closed.