Summary: Microsoft Scripting Guy, Ed Wilson, talks about using WMI Query Language and Windows PowerShell to get WMI data.
Hey, Scripting Guy! What is WQL? It sounds like SQL, but that does not always mean very much. I mean, General Electric and General Motors sound alike, but they do not have much in common. So back to my question, do you know what WQL is?
—WS
Hello WS,
Microsoft Scripting Guy, Ed Wilson, is here. Things are all in a flutter here in Charlotte, North Carolina in the United States. Our weather has been abysmal. It has been hovering around 105 degrees Fahrenheit (40.5 degrees Celsius, according to my conversion module). With all this heat, we began dreaming of cool places, and so we booked a trip to Germany. Unfortunately, it will not be until November, but at least we will escape the heat and get a chance to see many of our Windows PowerShell friends who we have met over the years and those who we want to meet. We already have three dates lined up in some of our favorite cities. Tonight, the best we can do is go out for dinner and a movie with Brian (one of our Charlotte Windows PowerShell User Group friends).
WS, of course I know what WQL is—I wrote the book on WMI: Microsoft Windows Scripting with WMI: Self-Paced Learning Guide. I am also contributing a chapter to a new book about Windows PowerShell and SQL Server 2012 written by Laerte Junior, Bob Beachumin, and Mark Broadbent.
WMI Query Language
Here is one of those “bad news” things. WQL is WMI Query Language. WMI stands for Windows Management Instrumentation. So one would think that WQL really is Windows Management Instrumentation Query Language; but it probably is not. There is documentation on MSDN, for example, WQL (SQL for WMI), but it is more or less COM based, and while it is comprehensive, it is more extensive than a typical Net Admin or IT Pro would need to do. The basic WQL statements that you need to know are Select, From, and Where.
Using the Select statement
A typical WMI query begins by using the Select statement to choose everything or only a few properties from a WMI class. To choose all properties from a WMI class, you use the asterisk (“*”). After you have selected the properties (one or more properties, or all of them), you use the From keyword to list which WMI class to query. The following script creates a WQL query that chooses all properties from the Win32_Bios WMI class:
$query = "Select * from Win32_Bios"
To choose a single property from the WMI class, you place the property name after the Select keyword and before the From keyword. In the following query, only the name of the BIOS is selected from the Win32_Bios WMI class.
$queryName = "Select Name from Win32_Bios"
If you want to select more than one property, you separate the property names by commas. Therefore, the following WMI query chooses the name and the version from the Win32_Bios WMI class.
$queryNameVersion = "Select name, version from WIn32_Bios"
Using the WQL query
So how do you use the WQL query to retrieve information from a system? In Windows PowerShell 2.0, there are two main ways to do this. The first is to use the Get-WmiObject cmdlet, and the second is to use the [wmisearcher] type accelerator. The [wmisearcher] type accelerator creates a ManagementObjectSearcher class. The ManagementObjectSearcher class is documented on MSDN, but the thing you really need to know how to use is the Get method. This will be discussed later in this section. In Windows PowerShell 3.0, the CIM cmdlets also accept a WQL query. I will talk about using the CIM cmdlets at a later date.
Query by using the Get-WmiObject cmdlet
The first way is to use the WQL query with the Get-WmiObject cmdlet. To do this, you use the Query parameter. The command is shown here:
PS C:\> $query = "Select * from Win32_Bios"
PS C:\> Get-WmiObject -Query $query
SMBIOSBIOSVersion : 8BET56WW (1.36 )
Manufacturer : LENOVO
Name : Default System BIOS
SerialNumber : R9FPY3P
Version : LENOVO – 1360
Let’s use our other queries to see how they fare. First, select only the name of the bios as shown here.
PS C:\> $queryName = "Select Name from Win32_Bios"
PS C:\> Get-WmiObject -Query $queryName
__GENUS : 2
__CLASS : Win32_BIOS
__SUPERCLASS :
__DYNASTY :
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
Name : Default System BIOS
Now, let’s choose the name and version query and use it.
PS C:\> $queryNameVersion = "Select name, version from WIn32_Bios"
PS C:\> Get-WmiObject -Query $queryNameVersion
__GENUS : 2
__CLASS : Win32_BIOS
__SUPERCLASS :
__DYNASTY :
__RELPATH :
__PROPERTY_COUNT : 2
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
Name : Default System BIOS
Version : LENOVO - 1360
Query by using the [wmisearcher] type accelerator
By using the [wmisearcher], you gain easy access to the ManagementObjectSearcher .NET Framework class. This provides you not only with the ability to query WMI for information, but also to configure the way that query is conducted. There are three basic steps to using the [wmisearcher] type accelerator.
Just the steps...
To use the [wmisearcher] type accelerator
- Put the WQL query in a variable.
- Use the [wmisearcher] to cast the WQL string into a ManagementObjectSearcher object.
- Call the Get method from the ManagementObjectSearcher object.
This may sound more complicated than it is. In fact, it is very simple. Here is an example of using WQL to return all of the properties from the Win32_Bios class.
Note Not all of the properties display due to the format*XML file that specifies which properties to return.
PS C:\> $query = "Select * from Win32_Bios"
PS C:\> $bios = [wmisearcher]$query
PS C:\> $bios.Get()
SMBIOSBIOSVersion : 8BET56WW (1.36 )
Manufacturer : LENOVO
Name : Default System BIOS
SerialNumber : R9FPY3P
Version : LENOVO – 1360
In the same way that WQL reduces the properties selected for use with the Get-WmiObject cmdlet, the same methodology can be used with the [wmisearcher] type accelerator. In the example shown here, only the Name property returns from the query.
PS C:\> $queryName = "Select Name from Win32_Bios"
PS C:\> $biosname = [wmisearcher]$queryName
PS C:\> $biosname.Get()
__GENUS : 2
__CLASS : Win32_BIOS
__SUPERCLASS :
__DYNASTY :
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
Name : Default System BIOS
But, rather than storing the string in a variable, then casting the string into a ManagementObjectSearcher type, and then calling the Get method, you can skip one of the steps and still have decent readability. This works because in the previous example, the WQL string was stored in a variable. The variable was then cast into the ManagementObjectSearcher type, and then the method was called. The code shown here skips one of the steps and casts the string directly to the object, and then stores the resulting object in the variable.
PS C:\> $biosname = [wmisearcher]"Select name from win32_bios"
PS C:\> $biosname.Get()
__GENUS : 2
__CLASS : Win32_BIOS
__SUPERCLASS :
__DYNASTY :
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
Name : Default System BIOS
A more interesting way of doing this (and perhaps a bit more readable) is to leave the WQL string on the right side of the equality operator, and perform the cast to ManagementObjectSearcher on the variable. This code is even cleaner, and it allows for easier modification of the WQL query.
PS C:\> [wmisearcher]$biosname = "Select name from win32_bios"
PS C:\> $biosname.Get()
__GENUS : 2
__CLASS : Win32_BIOS
__SUPERCLASS :
__DYNASTY :
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
Name : Default System BIOS
We can even perform this query in a single line. This works because the [wmisearcher] casts the WQL string to a ManagementObjectSearcher. From that object the Get method is available. By using the parentheses () to group the cast to the ManagementObjectSearcher first, the Get method becomes available.
PS C:\> ([wmisearcher]"Select name from win32_bios").get()
__GENUS : 2
__CLASS : Win32_BIOS
__SUPERCLASS :
__DYNASTY :
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
Name : Default System BIOS
Using the query directly
Of course, you do not have to store your query in a variable. You can type the query directly into the Query position in your command. Although this may have advantages in simplicity (you have one command instead of two), it also makes your code more difficult to read. This approach is shown here:
PS C:\> Get-WmiObject -Query "Select * from win32_bios"
SMBIOSBIOSVersion : 8BET56WW (1.36 )
Manufacturer : LENOVO
Name : Default System BIOS
SerialNumber : R9FPY3P
Version : LENOVO - 1360
WS, that is all there is to using WQL. WMI Week will continue tomorrow when I will talk about limiting information that is returned by the WQL query. I will also talk about all those extra system properties that were returned by WMI when we attempted to limit the properties.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy