Select-String Cmdlet Updates

The information in this article was written against the Community Technology Preview (CTP) of Windows PowerShell 2.0. This information is subject to change in future releases of Windows PowerShell 2.0.

Finding Text Using Select-String

The new remoting capabilities built into Windows PowerShell 2.0 represent the most-talked about feature of the recent Community Technology Preview (CTP) release. And for good reason: it is pretty to cool to be able to run PowerShell commands and PowerShell cmdlets against a remote computer. The truth is, even if that was the only change made to PowerShell that would be reason enough to download the CTP release. As it is, however, PowerShell 2.0 includes a number of other new features, ranging from brand-new cmdlets for working with WMI to useful little enhancements to existing cmdlets. Existing cmdlets like, say, the Select-String cmdlet.

The Select-String cmdlet is used to find target text within a file or a variable value. For example, suppose we saved the first paragraph of this article to a text file named C:\Scripts\Test.txt. Now, suppose we need to know whether this file contains the target string CTP. How could we determine whether the string CTP can be found anywhere in C:\Scripts\Test.txt? Like this:

Select-String C:\Scripts\Test.txt -pattern "CTP"

As you can see, this is a very simple little command: we just call Select-String followed: 1) by the item we want to search (C:\Scripts\Test.txt); and 2) the –pattern parameter (used to specify the target text; that is, the value we’re searching for). In return, Select-String will report back any matches that it found:

C:\scripts\test.txt:2:about feature of the recent Community Technology Preview (CTP) release. And for good reason:
C:\scripts\test.txt:5:would be reason enough to download the CTP release. As it is, however, PowerShell 2.0 includes

As long as we’re on the subject, we should point out that Select-String reports back the file path, the line number, and the actual line in the text file where the target value was found. In some cases, that might be more information than you need; maybe all you need is the line number. In that case, you can pipe the output to the Select-Object cmdlet and select only the properties (FilePath, LineNumber, Line) that you’re interested in:

Select-String C:\Scripts\Test.txt -pattern "CTP" | Select-Object LineNumber

Or, tack on the –quiet parameter and get back nothing more than a Boolean value (True or False) that tells you whether at least one instance of the target text could be found:

Select-String C:\Scripts\Test.txt -pattern "CTP" -quiet

In and of itself, that’s pretty cool. But in PowerShell 2.0 several new parameters have been added to Select-String, including two that we’ll talk about in this article: -notMatch and –context. Let’s see if we can figure out what these two parameters do.

The –notMatch Parameter

Select-String was originally designed to return all the instances (e.g., all the lines in a text file) where a match occurred. However, there might be times when you’re interested in all the instances where no match occurred. For example, suppose you have a very simple text file (C:\Scripts\Test.txt), that looks like this:

Failed
Failed
Succeeded
Postponed
Failed
Succeeded
Succeeded
Postponed
Failed

As you can see, we have several different options here: Failed, Succeeded, and Postponed. Suppose you wanted to get back information on all the lines that include the word Failed. That’s easy enough:

Select-String C:\Scripts\test.txt -pattern "failed"

Ah, but what if you want all the lines in the text file that don’t include the word Failed? In Windows PowerShell 1.0, there’s no easy way to get that information.

In Windows PowerShell 2.0, however, there is a very easy way to get that information:

Select-String C:\Scripts\test.txt -pattern "failed" -notMatch

See what we’ve done here? We’ve asked Select-String to search through Test.txt looking for all instances of the word failed. However, we also tacked on the –notMatch parameter; this tells the cmdlet to return any lines in the text file that don’t contain the target word. In other words, -notMatch tells the script to return information like this:

scripts\test.txt:3:Succeeded
scripts\test.txt:4:Postponed
scripts\test.txt:6:Succeeded
scripts\test.txt:7:Succeeded
scripts\test.txt:8:Postponed

As you can see, the only information we got back were those lines in the text file that don’t contain the word failed. Which is what we were hoping to get back.

The –context Parameter

Sometimes searching for a target value can result in slightly-misleading output. For example suppose you use this command to search a log file for the word failure:

Select-String C:\Scripts\Test.lxt -pattern "failure"

Now, suppose Select-String reports back the following:

scripts\test.txt:4:a) Name Resolution failure on the current domain controller.

Name resolution failure on the current domain controller? Uh-oh; sound the alarm!

But wait. As it turns out, this entry in the log file actually reads (in part) like this:

Processing Failed 10/30/2007 10:04:05 AM The processing of Group Policy did not succeed. Windows could not resolve the computer name. This could be caused by one or more of the following: a) Name Resolution failure on the current domain controller. b) Active Directory Replication Latency (an account created on another domain controller has not replicated to the current domain controller).

In other words, you might have a name resolution failure. But, then again, you might not; this is just one of several possible problems.

What that means is that context can be very important when extracting information from a text file. And that’s too bad, because context is something that the Select-String cmdlet simply cannot provide.

Well, not unless you use the –context parameter, that is.

As the name implies, the –context parameter not only finds matches but also lets you view those matches in context. That’s great. But what, exactly does that mean?

To answer that question, let’s modify our previous command by adding the –context parameter:

Select-String C:\Scripts\Test.lxt -pattern "failure" -context 2

What’s the 2 passed to –context for? That simply tells the script that, when it comes time to display any matches, we don’t want to see just the line of text where the match occurred. Instead, we also want to see the two lines of text immediately preceding that line as well as the two lines of text immediately following that line. In other words, we want output that looks like this (note that the line where the match occurred can be identified by the right angle bracket [>]):

  scripts\test.txt:2:The processing of Group Policy did not succeed. Windows could not resolve the
  scripts\test.txt:3:computer name. This could be caused by one or more of the following:
> scripts\test.txt:4:a) Name Resolution failure on the current domain controller.
  scripts\test.txt:5:b) Active Directory Replication Latency (an account created on another
  scripts\test.txt:6:domain controller has not replicated to the current domain controller).

That’s more like it; now we know that while we might have a Name Resolution failure we might also have some other problem instead (e.g., an Active Directory replication problem). That could save us from spending an enormous amount of time and energy pursuing a problem that doesn’t even exist.

If you prefer, you can specify different values for the lines preceding a match and the lines following a match. For example, this command shows us the 3 lines immediately preceding a matched line, as well as just the 1 line immediately following a matched line:

Select-String C:\Scripts\Test.lxt -pattern "failure" -context 3,1

Using our sample text, that results in output that looks like this:

  scripts\test.txt:1:Processing Failed 10/30/2007 10:04:05 AM
  scripts\test.txt:2:The processing of Group Policy did not succeed. Windows could not resolve the
  scripts\test.txt:3:computer name. This could be caused by one or more of the following:
> scripts\test.txt:4:a) Name Resolution failure on the current domain controller.
  scripts\test.txt:5:b) Active Directory Replication Latency (an account created on another

Very nice.

A bonus Select-String Tip. By default, Select-String does case-insensitive matching; that means the letter case is ignored which, in turn, means that both FAILURE and failure will be tagged as matches. If you’d prefer to perform a case-sensitive match, in which FAILURE and failure do not match, then simply add the –caseSensitive parameter.