WMI Query Language

By The Microsoft Scripting Guys

Sesame Script

Welcome to Sesame Script, the column for beginning script writers. The goal of this column is to teach the very basics of Windows scripting for system administration automation. We’ll provide you with the information you’ll need to begin reading and understanding scripts and to start modifying those scripts to suit your own needs. If there’s anything in particular about scripting you’re finding confusing, let us know; you’re probably not alone.

Check the Sesame Script Archives to see past articles.

On This Page

Speak the Local Language
What Does This Have to do with Scripting?
WMI Query Language
Wrap-Up

Speak the Local Language

One of the Scripting Guys recently spent a week in Germany. This was a last-minute trip with little preparation. You might be aware that Scripting Guy Peter Costantini can speak several languages. We’re not sure if German is one of them, but it doesn’t matter because this story isn’t about him, it’s about one of the other Scripting Guys. This other Scripting Guy, the one who went to Germany, can’t speak anything other than English, and maybe a few phrases of Spanish (which weren’t all that helpful in Germany). Fortunately most places the Scripting Guy went there was someone who spoke English, which was very considerate of them. The Scripting Guy quickly tried to at least pick up the basics: Danke, Schnitzel…that’s about as far as it went in a week.

While the kind German people at the tourist attractions, restaurants, and other places where you spend money were very accommodating, it would have been nice to have been able to communicate intelligently in the local language. (This would have been especially helpful when the Scripting Guy mistakenly wandered into the wrong part of Heidelberg Castle and was accidentally locked in for a short period of time.)

Scripting is kind of the same. You can communicate with Windows using the graphical tools, but at times this can be like gesturing to try and get your point across. Sometimes it works, but other times you can’t seem to get what you want as efficiently as you’d like, if at all. (The Scripting Guy also got locked out of a hotel after the front desk had closed, and the security guard didn’t speak English. It took a while to convince the guard, through various gestures, that the Scripting Guy really was a guest there, was locked out, and didn’t want to sleep outside on the patio furniture.)

And here’s another thing to consider. Even if you can speak the language you might get a little confused among the various dialects. For example, British English is different from Southeastern United States English which is different from Western United States English. Spain Spanish is different from Mexico Spanish. Portugal Portuguese is different from Brazil Portuguese. And so on.

What Does This Have to do with Scripting?

Don’t worry, as usual the Scripting Guys do have a point to make; it just takes us a little while to get there. In this case the point has to do with VBScript, Windows Script Host (WSH), Windows Management Instrumentation (WMI), and WMI Query Language (WQL).

Note Before you go on, you should have a basic understanding of objects and properties. See the Sesame Script article Class is in Session if you need a refresher.

VBScript

We use VBScript as the language to communicate directly with the computer. There’s no additional layer that creates a graphical interface: we talk almost directly to the computer through a series of statements such as If Then, Do Until, For Next, and so on. (We say almost directly because, truthfully, at its heart the computer communicates in a series of 1s and 0s. VBScript allows us to communicate in a language a little easier for us to understand.)

For example, here’s a simple statement comprised only of VBScript:

x = 4
If x > 3 Then
    y = 7
End If

But this article isn’t about VBScript.

WSH

Windows Script Host is another means of communication, one that determines how VBScript will run. WSH provides a runtime environment that allows scripts in many different languages (VBScript, Perl, etc.) to run. WSH also contains a small object model that provides objects that let you to do things like echo data back to the command windows. Here’s an example of a script that uses WSH and VBScript:

x = 4
If x > 3 Then
    Wscript.Echo x
End If

But this article isn’t about WSH.

WMI

WMI is not actually a language, it’s an object model. WMI provides us with the objects, methods and properties we need to be able to communicate with the different parts of the operating system. For example, you can use WMI to access processes and services, disk drives, registry settings, and so on. Here’s an example of a script that uses WMI, WSH, and VBScript:

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

Set colItems = objWMIService.ExecQuery("Select * from Win32_PnPEntity")

For Each objItem in colItems
    Wscript.Echo "Description: " & objItem.Description
    Wscript.Echo "Manufacturer: " & objItem.Manufacturer
    Wscript.Echo "Name: " & objItem.Name
    Wscript.Echo "Service: " & objItem.Service
    Wscript.Echo
Next

This script uses GetObject to connect to the WMI service on the local computer. (You can also use this script to connect to a remote computer simply by changing the value of strComputer to the name of the remote machine.) The next thing this script does is to run the ExecQuery method on the WMI service object.

But this article isn’t about WMI (not really anyway).

However, it is about that string in quotes that is passed as a parameter to ExecQuery.

More Information

For more on VBScript see the VBScript Primer in the Windows 2000 Scripting Guide.

For more on WSH see the WSH Primer in the Windows 2000 Scripting Guide.

For more on WMI see the WMI Scripting Primer in the Windows 2000 Scripting Guide.

WMI Query Language

WMI Query Language (WQL) isn’t so much a dialect as it is a language within a language. You use a scripting language such as VBScript to access and manipulate WMI objects, but you use WQL to retrieve the exact object or objects you want to work with.

As you’ve probably gathered from the name, WQL is a query language, much like SQL, a standard used to query databases. WQL is actually a subset of SQL, so if you’re familiar with SQL you’re way ahead of the game on this one. In the same way that we use If Then and For Next statements to talk to the computer in VBScript, we use specific statements to talk to WMI to retrieve objects. In order to understand the language, we need to look at some of these statements.

Select

The statement you’ll see most, and absolutely can’t do without, is the Select statement. This is how you start a query, by saying that you want to Select something. The Select keyword is followed by what it is you want to select. Let’s take a look at the call to ExecQuery in our previous example:

Set colItems = objWMIService.ExecQuery("Select * from Win32_PnPEntity")

And now let’s take a look at only the WQL:

Select * from Win32_PnPEntity

We start with our Select keyword. What is it we want to select? In this case we want to select everything, which is represented with the wildcard character (*). But we’re not done there; after all, we can’t really say we want to select everything. What exactly would “everything” be? Instead we need to add another keyword, the From keyword, and narrow the query down to everything from…where? Well, everything from the Win32_PnPEntity class. Or, more accurately, all the properties associated with all the instances of the Win32_PnPEntity class.

In other words, we’re telling WMI to give us all the properties for all the objects on the computer that that the Win32_PnPEntity class knows about. The Win32_PnPEntity class represents all the plug-and-play hardware on a machine, so we’ll actually get back quite a bit of information. If we run a script that selects all the Win32_PnPEntity references and then displays some information about each object, here’s a sampling of the type of data we’ll get back:

Description: ACPI Multiprocessor PC
Manufacturer: (Standard computers)
Name: ACPI Multiprocessor PC
Service: \Driver\ACPI_HAL

Description: Microsoft ACPI-Compliant System
Manufacturer: Microsoft
Name: Microsoft ACPI-Compliant System
Service: ACPI

Description: ACPI Power Button
Manufacturer: (Standard system devices)
Name: ACPI Power Button
Service:

Description: Intel Processor
Manufacturer: Intel
Name: Intel(R) Pentium(R) 4 CPU 2.80GHz
Service: intelppm

Description: Intel Processor
Manufacturer: Intel
Name: Intel(R) Pentium(R) 4 CPU 2.80GHz
Service: intelppm
...

That’s great information, but maybe it’s more information than you really wanted. Suppose you wanted only the description of each device and not the manufacturer, name, and service? That seems simple enough; just don’t echo the other properties:

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

Set colItems = objWMIService.ExecQuery("Select * from Win32_PnPEntity")

For Each objItem in colItems
    Wscript.Echo "Description: " & objItem.Description
    Wscript.Echo
Next

Yes, that works. However, there’s a more efficient way to do this. Instead of using the wildcard character to say we want to select everything, we specify the property or properties of the Win32_PnPEntity class we want to retrieve:

Select Description from Win32_PnPEntity

A script using this query will probably run a little bit faster. That isn’t a big deal with this particular query, but it can come in handy with queries that return larger amounts of data. (Even then the performance improvement is often-times negligible, but this is still a useful thing to know about, because the knowledge transfers to other situations where you might use some sort of query language.)

But hang on, let’s see what happens when we plug this new query into our original script:

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

Set colItems = objWMIService.ExecQuery("Select Description from Win32_PnPEntity")

For Each objItem in colItems
    Wscript.Echo "Description: " & objItem.Description
    Wscript.Echo "Manufacturer: " & objItem.Manufacturer
    Wscript.Echo "Name: " & objItem.Name
    Wscript.Echo "Service: " & objItem.Service
    Wscript.Echo
Next

When we run this script we get the following output:

Description: ACPI Multiprocessor PC
C:\Scripts\begin\test.vbs(10, 5) Microsoft VBScript runtime error: 
Object doesn't support this property or method: 'objItem.Manufacturer'

As you can see, the script echoed back the Description, but then returned an error message when it reached the next Wscript.Echo statement. Why is that? Well, remember, we’re no longer retrieving everything, meaning we’re not asking WMI to give us all the properties associated with the Win32_PnPEntity object. Instead we’ve asked WMI to give us only the information contained in the Description property.

Look at it this way: If you order just a cheeseburger rather than the whole value meal that includes fries and a cola, you’ll be able to take a bite out of the cheeseburger but you won’t have much luck when you get thirsty and reach for the cola - you never asked for it so it’s not there. In the same way, when we try to echo the contents of the Manufacturer property we’re not able to do that because we never retrieved that information; we asked for only the Description, so that’s all we got. Therefore we need to adjust our script accordingly:

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

Set colItems = objWMIService.ExecQuery("Select Description from Win32_PnPEntity")

For Each objItem in colItems
    Wscript.Echo "Description: " & objItem.Description
    Wscript.Echo
Next

And now we get our output:

Description: ACPI Multiprocessor PC
Description: Microsoft ACPI-Compliant System
Description: ACPI Power Button
Description: Intel Processor
Description: Intel Processor
Description: PCI bus
Description: Intel(R) 915G/P/GV Processor to I/O Controller - 2580
Description: Intel(R) 915G/P/GV PCI Express Root Port - 2581
…

Remember when we said “specify the property or properties?” That should have been a hint to you that you can retrieve more than one property. And how do we do that? Like this:

Select Description, Manufacturer from Win32_PnPEntity

We simply separate the property names with commas. We can now put this query into our script and echo back the Description and Manufacturer information. Go ahead and take a sip of that cola now.

Where

Let’s go back to our WMI script that retrieves all the properties from all the Win32_PnPEntity objects on the computer:

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

Set colItems = objWMIService.ExecQuery("Select * from Win32_PnPEntity")

For Each objItem in colItems
    Wscript.Echo "Description: " & objItem.Description
    Wscript.Echo "Manufacturer: " & objItem.Manufacturer
    Wscript.Echo "Name: " & objItem.Name
    Wscript.Echo "Service: " & objItem.Service
    Wscript.Echo
Next

We now know that we can narrow down which properties we retrieve by replacing the wildcard character with the property names. But this time rather than retrieving some properties for all objects, we want to retrieve all properties for some objects. We do that with a Where clause. Suppose, for example, we’re interested in only the devices from Microsoft. In that case we want to tell WMI to give us all the properties for all Win32_PnPEntity objects where the Manufacturer is Microsoft. And we do that like this:

Select * from Win32_PnPEntity Where Manufacturer = 'Microsoft'

You can see we start out with our regular Select statement, then we’ve added on a Where clause:

Where Manufacturer = 'Microsoft'

This clause tells WMI we only want the Win32_PnPEntity objects whose Manufacturer property has a value of “Microsoft”. If we plug this new query into our script, we’ll echo back information about all the plug-and-play devices on the computer that were manufactured by Microsoft:

Description: Microsoft ACPI-Compliant System
Manufacturer: Microsoft
Name: Microsoft ACPI-Compliant System
Service: ACPI

Description: HID-compliant consumer control device
Manufacturer: Microsoft
Name: HID-compliant consumer control device
Service:

Description: Microsoft USB Laser Mouse 6000 (IntelliPoint)
Manufacturer: Microsoft
Name: Microsoft USB Laser Mouse 6000 (IntelliPoint)
Service: mouhid
...

We’re also able to get even more specific. Let’s say we want all the devices manufactured by Microsoft that have a specific name. We can combine multiple criteria like this by using the And keyword, like this:

Where Manufacturer = 'Microsoft' and Name = 'wan miniport (ip)'

When we plug this Where clause into our script our output looks like this:

Description: WAN Miniport (IP)
Manufacturer: Microsoft
Name: WAN Miniport (IP)
Service: NdisWan

Notice that we added the And keyword and followed that with the second condition we want to place on our query. In this case we want to retrieve only devices manufactured by Microsoft that have the name WAN Miniport (IP). Also notice that the query is not case-sensitive. We specified wan miniport (ip) in our query, but our output shows the property as having a value of WAN Miniport (IP). These are equivalent to WQL.

Windows XP and Later

With Windows XP and later you can use wildcards in your queries. For example, let’s say we want to retrieve all the WAN Miniport devices, not just the IP device. We can do that with this query:

Select * from Win32_PnPEntity Where Manufacturer = 'Microsoft' and Name Like 'wan miniport%'

This query looks the same as the last one until you get past the And keyword. Instead of checking for Name equals (Name = ) we check for Name Like. This tells WMI we want all instances of Win32_PnPEntity where the Name property has a value that matches the string we specify. As you can see, the string we have specified begins with wan miniport, but at the end we’ve added a percent character (%). This is the wildcard character in a WQL Where clause. This character represents any character or string of characters. That means that what we’re really asking for is a Name that starts with wan miniport and ends with any other character or set of characters. When we run the script with this new query, this is what our output looks like:

Description: WAN Miniport (L2TP)
Manufacturer: Microsoft
Name: WAN Miniport (L2TP)
Service: Rasl2tp
Description: WAN Miniport (IP)
Manufacturer: Microsoft
Name: WAN Miniport (IP)
Service: NdisWan
Description: WAN Miniport (PPPOE)
Manufacturer: Microsoft
Name: WAN Miniport (PPPOE)
Service: RasPppoe
Description: WAN Miniport (PPTP)
Manufacturer: Microsoft
Name: WAN Miniport (PPTP)
Service: PptpMiniport
Description: Packet Scheduler Miniport
Manufacturer: Microsoft
Name: WAN Miniport (IP) - Packet Scheduler Miniport
Service: PSched

As you can see, we’ve retrieved all instances of Win32_PnPEntity objects whose Manufacturer is Microsoft and whose Name begins with WAN Miniport.

Another way to get more specific results from our queries is by using the Or keyword. We use this in the exact same way we used the And keyword, but this time instead of narrowing down our results we’ll be expanding them. It’s actually pretty simple if you think about it. Suppose you go to buy a new car and you want to look only at cars that have all-wheel drive (AWD) and a navigation system. In that case the salesperson would be wasting your time if he or she led you over to a car that had a navigation system but only had front-wheel drive. The car must meet both criteria or you’re not interested. On the other hand, suppose you’re looking to save a little money and are trying to decide between the two options. In that case you’d like to look at any car that has AWD or any car that has a navigation system.

Your query will work the same way. Let’s say that instead of narrowing your query to all Microsoft devices you also want to see all Intel devices. You would do that using Or:

Select * from Win32_PnPEntity Where Manufacturer = 'Microsoft' or Manufacturer = 'Intel'

When we run our script with this query, we get back object references to all devices that meet either of these criteria:

Description: Microsoft ACPI-Compliant System
Manufacturer: Microsoft
Name: Microsoft ACPI-Compliant System
Service: ACPI

Description: Intel Processor
Manufacturer: Intel
Name: Intel(R) Pentium(R) 4 CPU 2.80GHz
Service: intelppm
...

Keep in mind that you can combine And and Or statements in your Where clause, although WQL does have restrictions on how long and complicate a query can be. Those restrictions vary, but just try to be reasonable about it and don’t try to get too fancy.

Wrap-Up

What you’ve seen here is the equivalent of learning the basic catch-phrases in another language: Hello; Goodbye; Thank You; Where’s the bathroom?; and so on. There’s a little more to WQL than what we’ve explored here, but this is what you’ll need to get by without getting locked in our out of anyplace or gesturing wildly. Enjoy your time with WQL, and say “hi” to the locals for us.