Filtering output from Windows PowerShell
With PowerShell, it's pretty simple to browse Windows Management Instrumentation classes without cheating by filtering the content -- all it takes is a new cmdlet and working with variables.
Last month, we did a little work with Windows Management Instrumentation (WMI) to show you how Windows PowerShell interacts with external providers. In that column, we did some disk inventory, then filtered and formatted the output, to make it show only a selected portion of the possible output.
You may have noticed one glaring omission in the beginning of that exercise. Remember when we were starting out and I was able to get going because I knew the name of the class I needed to work with? As I said at the time (and as you'll see if you use the –list argument to get-wmi), there are hundreds of classes. I can't remember all the words to Joy to the World, so I plainly can't remember the name of every single WMI class out there. For the sake of that example, I had to cheat a little bit and use a class I knew before I started.
Let's make it a little easier to browse WMI classes without cheating by filtering the content. The good news is that this is pretty simple—all it takes is a new cmdlet and working with variables.
Basic text filtering
Filtering output by text in VBScript requires messing around with regular expressions. While PowerShell supports regular expressions, it doesn't require them. Instead, you can use the Select-String cmdlet. At its simplest, it works like this: Feed this cmdlet the information to search, and it will find the text you're looking for:
"PowerShell", "Seashell", "Monad" | select-string -pattern "PowerShell"
In this command, you're creating three strings and piping them to Select-String, telling them that the string you're looking for reads "PowerShell". That is exactly what this command will do. Just be careful to type this command exactly as it's written here. Add extra spaces, and you may get an error. But looking for complete strings isn't always helpful. What if you want to find all strings that have the word "shell" in them? To do that, you'd amend the command slightly so that the argument to –pattern was "shell."
"PowerShell", "Seashell", "Monad" | select-string -pattern "shell"
That command will return both "PowerShell" and "Seashell."
Select-String is case-insensitive by default, but doesn't have to be. Let's change this example slightly.
"Powershell", "Seashell", "Monad" | select-string -pattern "shell" –casesensitive
Although the word "shell" appears in both "PowerShell" and "Seashell," the above command will return only "Seashell."
Searching files
Filtering the text you just typed in isn't the most likely scenario. It's more useful to find entries that match when you don't know what's out there and it's a ton of data. You can use Google Desktop to find files on your computer. You can use Select-String as a simple variant of Google Desktop to search files.
For example, say I'm back working on a script and need some code examples for Select Case. I know there's a repository of sample scripts, but I don't want to search through all of them when I don't know whether they contain the code I need. Therefore, I can use select-string to search those files in the directory containing the repository, as in the example below. (Had I wanted to search the current folder, I would not have needed to provide the path.) The output will be the relevant line from each script, as shown here.
Select-string -path "c:scripts*.vbs" "Select Case"
C:scriptsconcatenate.vbs:2:Select Case Wscript.Arguments(0
C:scriptsenhanced.vbs:7:Select Case sInput
C:scriptssmartmapinventory.vbs:4:Select Case
colNamedArgs.Exists("name")
Now I can open the script files to see how Select Case is used.
Filtering variable content
Now that you've got the idea, let's filter the results of a command. As we said at the outset, that's where we are with get-wmi –list. Type it, and you've got a ton of output—more than you can easily browse. To make it easier to deal with, we'll do that search for WMI objects, but save it to a variable.
Variables in PowerShell begin with a dollar sign, i.e., $variable. To assign a value to a variable (we'll start with something simple), just set them equal to each other, like this:
$myvariable = 123
or
$myvariable = "Now is the time for all good men"
or even
$myvariable = get-date
to set the value of $myvariable equal to the current date. To view the contents of a variable, just type its name at the command prompt.
As you might guess, it's easy to shove the excruciatingly long list you get from get-wmi –list into a variable.
$wmi = Get-Wmiobject –list
Now that that list is stored in the variable, let's cut it down to size a bit with Select-String before we have to look at it.
$wmi | select-string -pattern "Win32_"
This command will return all WMI classes with names including the string "Win32_". This narrows the field to the classes we'll use in Windows. But this is still a long list -- how about narrowing the field a bit more? Maybe we'd like to see only the results with the word "network" in them. We'll do exactly what we did before—assign the results of a command to a variable. Only this time our new variable, $w32wmi, will contain only the classes from our first search. Now that we've got that, we can begin running new searches on it:
$w32wmi | select-string -pattern "Network"
Now we're getting some manageable output:
VISIONTHINGROOTcimv2:Win32_TSNetworkAdapterSettingError
VISIONTHINGROOTcimv2:Win32_NetworkClient
VISIONTHINGROOTcimv2:Win32_NetworkProtocol
VISIONTHINGROOTcimv2:Win32_NetworkAdapter
VISIONTHINGROOTcimv2:Win32_NetworkConnection
VISIONTHINGROOTcimv2:Win32_PerfRawData_Tcpip_NetworkInterface
VISIONTHINGROOTcimv2:Win32_PerfFormattedData_Tcpip_NetworkInterface
VISIONTHINGROOTcimv2:Win32_SystemNetworkConnections
VISIONTHINGROOTcimv2:Win32_TSNetworkAdapterSetting
VISIONTHINGROOTcimv2:Win32_TSNetworkAdapterListSetting
VISIONTHINGROOTcimv2:Win32_NetworkLoginProfile
VISIONTHINGROOTcimv2:Win32_NetworkAdapterConfiguration
VISIONTHINGROOTcimv2:Win32_NetworkAdapterSetting
Having done all this, I can easily go through the output to find the class I need for my task. (If I'm not sure which one I need, I still need to look through them, but if I'm pretty sure and just needed to check spelling, this would help a lot.) If I'd like to expand my search, I can just add a second parameter to Select-String:
$w32wmi | select-string -pattern "Network", "Disk"
Adding a second search parameter makes the search act like a Boolean OR statement, not an AND statement. That is, this search will return all classes that include the word "Network" OR "Disk", not just the ones that contain both.
In conclusion, this article has looked at one more essential part of working with PowerShell—searching within your results to find the exact information you needed. Filtering information with Select-String is easy. Get the data to filter, whether it's a string, a file or command output, and pipe it to the command for processing. This makes it much easier to work with WMI when you're not sure of the class names, and lets you easily find files with particular information.
Read all of Christa Anderson's scripting columns on SearchWinComputing.com.
ABOUT THE AUTHOR: |
Christa Anderson A Terminal Services MVP, Christa Anderson is the strategic technology manager for visionapp She formerly was program manager for the Microsoft Terminal Services team. She is an internationally known authority on scripting, the author of Windows Terminal Services, The Definitive Guide to MetaFrame XP, and co-author of the book Mastering Windows 2003 Server. If you have a scripting question for Christa, please email her at [email protected]. She often uses these emails as fodder for her scripting columns. |