Learn about Windows PowerShell
Hey, Scripting Guy! I have a problem using the Win32_Volume WMI class on my Windows Vista computer. I keep getting an error. I have searched the Internet using Bing and other search engines, but I cannot find the answer to my problem. It should be so simple; all I want to do is filter the results by the drive name in the WMI query. How hard can that be? Evidently, pretty **&&#!!@#$%^ hard! I have wasted more than four hours on this seemingly trivial task (and I am still behind from Thanksgiving break). I know I can pipe the results to the Where-Object cmdlet and filter the results that way, but I want to know why the Win32_Volume WMI class does not support filtering on the name property.
Microsoft Scripting Guy Ed Wilson here. Tea is one of life’s simple pleasures. This afternoon I am enjoying a special treat. The Scripting Wife presented me with a new teapot (I broke the lid on my little blue teapot the other day), and I decided to christen it with a pot of Lapsang souchong tea. It is a smoked tea with a strong flavor. It is one of the few teas to which I routinely add milk. The milk mellows out the flavor and really heightens the enjoyment of the tea. I am listening to The Nutcracker while reading e-mail sent to firstname.lastname@example.org and really having a lovely day.
NR, I am so sorry that you are obviously not having a very good day. In your case, a cup of tea and some uplifting classical music probably will not help. So, let us dive in and see what is causing your problem with the Win32_Volume WMI class.
Note: Portions of today's Hey, Scripting Guy! post are excerpted from the Microsoft Press book, Windows PowerShell 2.0 Best Practices by Ed Wilson, which is now available for pre-order.
While the Internet is a great source of information, it often can lead to more confusion than to clarity. This is because when you locate a source of information, it has not been updated to reflect the current version of the operating system. This situation is growing worse and not better because of a variety of complicating factors such as User Account Control (UAC), Windows Firewall, and other security factors that have so many different configuration settings. As an example suppose you decide to use the Win32_Volume WMI class to determine information about your disk drives. The first thing you will need to do is realize that the WMI class does not exist on any operating system older than Windows Server 2003. It is a bit surprising that the class does not exist on Windows XP. However, if you try the following command on Windows Vista, it generates an error:
Get-WmiObject -Class win32_volume -Filter "Name = 'c:\'"
The first suspect when dealing with Windows Vista and later is user rights. So maybe you open the Windows PowerShell console as an administrator and try the code again. It fails, however; so perhaps you wonder if it has something to do with the difference between expanding quotes and literal quotes. After contemplation, you decide to write the filter to take advantage of literal strings. The problem with this is that you have to escape the quotes, which is more work, but if it works, it is worth the effort. So you come up with the following code; unfortunately, it also fails when run:
Get-WmiObject -Class win32_volume -Filter 'Name = ''c:\'''
This time, maybe you decide to actually read the error message. Here is the error that was produced by the previous command:
Get-WmiObject : Invalid queryAt line:1 char:14+ Get-WmiObject <<<< -Class win32_volume -Filter "Name = 'c:\' " + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], Managemen tException + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.C ommands.GetWmiObjectCommand
You home in on the line that says, “Invalid query,” and decide that maybe the backward slash is a special character. When this is the problem, you need to escape the backward slash, and you decide to use the escape character to make one more attempt. Here is the code you come up with:
Get-WmiObject -Class win32_volume -Filter "Name = 'c:`\' "
Though that was a good idea, the code still does not work. It once again generates an error, which is seen here:
Get-WmiObject : Invalid queryAt line:1 char:14+ Get-WmiObject <<<< -Class win32_volume -Filter "Name = 'c:`\' " + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], Managemen tException + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.C ommands.GetWmiObjectCommand
The next thing to do is to see if you even have rights to run the query (I know you are running the console with Administrator rights, but there are some things that deny access even to the administrator, so it is best to check). The easiest way to do this is to perform the WMI query and omit the filter parameter. This is shown here:
Get-WmiObject -Class win32_volume
This command runs without generating any errors. You might think that because the WMI class seems to be a bit weird, maybe you cannot filter it at all. So perhaps you decide to write a different filter and see if it will accept that syntax. Maybe you come up with the following line of code:
Get-WmiObject -Class win32_volume -Filter "DriveLetter = 'c:'"
The above command rewards you with a nice output similar to the one seen here:
When working with scripting, network administrators and consultants often end up using workarounds. After all, our job is to get stuff working. Sometimes, The Scripting Guy ends up using workarounds as well. After all, my job is to write a daily Hey Scripting Guy! blog post, which means I have a deadline every single day of the week. In the situation with the Win32_Volume WMI class, I ended up always using the DriveLetter property when performing the WMI query. After several hours of experimentation, I ended up figuring that maybe the Name property was broken and avoided using it when doing demonstrations back when I was teaching classes. Luckily, I never had a student ask me why I used DriveLetter instead of the Name property in any of my queries. If they had asked, I guess I would have demonstrated that it did not work. Of course, if I had been asked in class, I would also have asked the WMI team why the query did not work, and perhaps found an answer sooner than I did. Of course, when I get an e-mail that specifically asks about using the Name property, it is a different story.
If you go back to the error message that was generated by the earlier queries, the InvalidOperation CategoryInfo field might cause you to look again at the backward slash. The earlier attempts to escape the backward slash were on the right track. The problem is the strange mixture of the WMI Query Language (WQL) syntax and Windows PowerShell syntax. The –filter parameter is Windows PowerShell syntax, but inside the parameter, you must supply a string that conforms to WQL dialect. This is why you use the equal sign for an operator instead of the Windows PowerShell –eq operator. The value assigned to the –filter parameter is passed to WMI, and WMI does not know what to do with an –eq operator. To escape the backward slash in WQL syntax, you must use another backward slash as is done in C or C++ syntax. Here is code that will filter out the drive based upon the name of the drive:
Get-WmiObject -Class win32_volume -Filter "Name = 'c:\\'"
NR, that is all there is to using the Win32_Volume WMI class. WMI Week will continue tomorrow.
If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at email@example.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
Nice. Escaping often escapes my comprehension :)