PowerShell Select User Specified Rows with Where-Object

The more I learn about PowerShell, the more I come to love the Where-Object and Select-Object commandlets.  Those two commands make life so much easier, especially when dealing with large data sets.  I've been working on just such a script lately and, in an effort to make it easier for other people to use, I've decided that I want to make the output table (which is going into an HTML file) user definable.  By using Where-Object and Select-Object, I can accomplish exactly this, although there was a bit of a learning curve.

In this post, I'm going to discuss Where-Object.  Where-Object allows us to select rows from the source material.  I took the user's input into a variable and simply used that in my Where-Object structure.  Let's look at an example!  First, let's prepare an object to be manipulated with the following code:

$myList = get-eventlog system -newest 15

That command will populate the $myList variable with the latest 15 entries from your system log, which will give us a few rows and columns to manipulate.  If we only wanted to see rows that are marked as "warning" in the EntryType column, we can simply use this command:

$myList | where {$_.EntryType -eq "warning"}

What if we want the user to be prompted for what type of event to display?  Easy; just prompt the user for input, store that input in a variable and use that variable  in the "Where-Object" command.

$userIn = read-host "Enter the Entry Type"
$myList | where {$_.EntryType -eq $userIn}

When you execute those two lines, it will prompt the user for an entry type and display the appropriate lines.  What if they want to specify multiple row types (both Information and Warning, for example)?  I do that with a ForEach loop, although I'm curious if anyone else has a more elegant solution.

$userIn = read-host "Enter the Entry Type(s) seperated by commas"
$userIn = ($userIn -split ",").trim()
foreach ($thisIn in $userIn){$myList | where {$_.EntryType -eq $thisIn}}

We've used -split in order to turn the user's input string into an array of strings (using commas to split into multiple items in the array).  I threw in that .trim() because people tend to put spaces after commas and I wanted to strip those out (otherwise our -eq logic wouldn't work, because "warning" does not equal " warning").  After the user's input has been processed, we enter a small foreach loop where the script returns all lines that match the first item in the array, then all lines that match the second, etc.

The final point that I want to make about Where-Object isn't really about Where-Object at all, but it's where I've tripped over this issue in the past.  When comparing strings with -eq, PowerShell is very literal.  You can see this easily enough by typing the following three lines:

"warning" -eq "warning"
"warning" -eq "warnin*"
"warning" -eq "warnin.*"

The first command returns true (good thing!), as "warning" does in fact equal "warning".  Notice that both of the other two commands returned false though.  This is because -eq compares the literal strings and does not interpret wildcards or regular expressions.  When matching strings with Where-Object, remember this fact!  Using -eq means that the strings must be exact matches; wildcards are not allowed!  How do you use wildcards?  Try these on for size:

"warning" -like "warning"
"warning" -like "warnin*"
"warning" -like "warnin.*"

Now, the first two return true (although the last is still false)!  If you want to use a simple wildcard, use -like instead.  What if you really, really want to use a regular expression?  Here you go:

"warning" -match "warning"
"warning" -match "warnin*"
"warning" -match "warnin.*"
"warning" -match "w"

I hope this helps!


Popular posts from this blog

Orphaned VMDK Files

Migrating from one vCenter to Another, Improved

Copying VM Folders and Permissions from One vCenter to Another