Welcome PowerShell User! This recipe is just one of the hundreds of useful resources contained in the PowerShell Cookbook.

If you own the book already, login here to get free, online, searchable access to the entire book's content.

If not, the Windows PowerShell Cookbook is available at Amazon, or any of your other favourite book retailers. If you want to see what the PowerShell Cookbook has to offer, enjoy this free 90 page e-book sample: "The Windows PowerShell Interactive Shell".

9.4 Search a File for Text or a Pattern

Problem

You want to find a string or regular expression in a file.

Solution

To search a file for an exact (but case-insensitive) match, use the -Simple parameter of the Select-String cmdlet:

Select-String -Simple SearchText file.txt

To search a file for a regular expression, provide that pattern to the Select-String cmdlet:

Select-String "\(...\) ...-...." phone.txt

To recursively search all *.txt files for a regular expression, pipe the results of Get-ChildItem to the Select-String cmdlet:

Get-ChildItem *.txt -Recurse | Select-String pattern

Or, using built-in aliases:

dir *.txt -rec | sls pattern

Discussion

The Select-String cmdlet is the easiest way to search files for a pattern or specific string. In contrast to the traditional text-matching utilities (such as grep) that support the same type of functionality, the matches returned by the Select-String cmdlet include detailed information about the match itself:

PS > $matches = Select-String "output file" transcript.txt
PS > $matches | Select LineNumber,Line

                        LineNumber Line
                        ---------- ----
                                 7 Transcript started, output file...

With a regular expression match, you’ll often want to find out exactly what text was matched by the regular expression. PowerShell captures this in the Matches property of the result. For each match, the Value property represents the text matched by your pattern:

PS > Select-String "\(...\) ...-...." phone.txt | Select -Expand Matches

...
Value    : (425) 555-1212

...
Value    : (416) 556-1213

If your regular expression defines groups (portions of the pattern enclosed in parentheses), you can access the text matched by those groups through the Groups property. The first group (Group[0]) represents all of the text matched by your pattern. Additional groups (1 and on) represent the groups you defined. In this case, we add additional parentheses around the area code to capture it:

PS > Select-String "\((...)\) ...-...." phone.txt |
    Select -Expand Matches | Foreach { $_.Groups[1] }

Success  : True
Captures : {425}
Index    : 1
Length   : 3
Value    : 425

Success  : True
Captures : {416}
Index    : 1
Length   : 3
Value    : 416

If your regular expression defines a named capture (with the text ?<Name> at the beginning of a group), the Groups collection lets you access those by name. In this example, we capture the area code using AreaCode as the capture name:

PS > Select-String "\((?<AreaCode>...)\) ...-...." phone.txt |
     Select -Expand Matches | Foreach { $_.Groups["AreaCode"] }

Success  : True
Captures : {425}
Index    : 1
Length   : 3
Value    : 425

Success  : True
Captures : {416}
Index    : 1
Length   : 3
Value    : 416

By default, the Select-String cmdlet captures only the first match per line of input. If the input can have multiple matches per line, use the -AllMatches parameter:

PS > Get-Content phone.txt
(425) 555-1212
(416) 556-1213 (416) 557-1214

PS > Select-String "\((...)\) ...-...." phone.txt |
    Select -Expand Matches | Select -Expand Value

(425) 555-1212
(416) 556-1213

PS > Select-String "\((...)\) ...-...." phone.txt -AllMatches |
    Select -Expand Matches | Select -Expand Value

(425) 555-1212
(416) 556-1213
(416) 557-1214

For more information about captures, named captures, and other aspects of regular expressions, see Appendix B.

Note

If the information you need is on a different line than the line that has the match, use the -Context parameter to have that line included in Select-String’s output. PowerShell places the result in the Context.PreContext and Context.PostContext properties of Select-String’s output.

If you want to search multiple files of a specific extension, the Select-String cmdlet lets you use wildcards (such as *.txt) on the filename. For more complicated lists of files (which includes searching all files in the directory), it is usually better to use the Get-ChildItem cmdlet to generate the list of files as shown previously in the Solution.

Since the Select-String cmdlet outputs the filename, line number, and matching line for every match it finds, this output may sometimes include too much detail. A perfect example is when you are searching for a binary file that contains a specific string. A binary file (such as a DLL or EXE) rarely makes sense when displayed as text, so your screen quickly fills with apparent garbage.

The solution to this problem comes from Select-String’s -Quiet switch. It simply returns true or false, depending on whether the file contains the string. So, to find the DLL or EXE in the current directory that contains the text “Debug”:

Get-ChildItem | Where { $_ | Select-String "Debug" -Quiet }

Two other common tools used to search files for text are the -match operator and the switch statement with the -file option. For more information about those, see Recipe 5.7 and Recipe 4.3. For more information about the Select-String cmdlet, type Get-Help Select-String.

See Also

Recipe 4.3, “Manage Large Conditional Statements with Switches”

Recipe 5.7, “Search a String for Text or a Pattern”

Appendix B, Regular Expression Reference