PowerShell Search for Text in Files with Select-String

A customer reports an error. The log folder has 200 files. You need to find every occurrence of that error across all of them, with line numbers, in under five seconds. Select-String is exactly the right tool — it’s PowerShell’s equivalent of grep, but it returns structured match objects instead of text lines, which means you can filter, sort, and export the results. This guide covers how to PowerShell search text in files from a single file to recursive multi-folder scans.
Quick Answer / TL;DR
# Search a single file for a pattern
Select-String -Path 'C:\Logs\app.log' -Pattern 'ERROR'
# Search all .log files recursively
Get-ChildItem 'C:\Logs' -Filter '*.log' -Recurse |
Select-String -Pattern 'ERROR'
Search a Single File
Select-String returns MatchInfo objects with file name, line number, and the matching line:
# Basic search
Select-String -Path 'C:\Logs\app.log' -Pattern 'ERROR'
# Show just the essential fields
Select-String -Path 'C:\Logs\app.log' -Pattern 'ERROR' |
Select-Object Filename, LineNumber, Line
# Count matches
(Select-String -Path 'C:\Logs\app.log' -Pattern 'ERROR').Count
C:\Logs\app.log:15:2026-05-04 08:15:33 ERROR Database connection failed
C:\Logs\app.log:47:2026-05-04 09:01:12 ERROR Timeout on request ID 8821
C:\Logs\app.log:112:2026-05-04 09:55:44 ERROR Null reference in ProcessOrder()
The output format is filename:linenumber:content when displayed. As objects, they have .Filename, .LineNumber, .Line, .Matches, and other properties.
Search Multiple Files with Wildcards
Pass a wildcard path to search multiple files at once:
# All .log files in a directory
Select-String -Path 'C:\Logs\*.log' -Pattern 'CRITICAL'
# Multiple file types
Select-String -Path 'C:\Config\*.json', 'C:\Config\*.xml' -Pattern 'password'
# Pipe Get-ChildItem for more control
Get-ChildItem 'C:\Logs' -Filter '*.log' |
Select-String -Pattern 'Connection refused'
C:\Logs\app.log:88:2026-05-04 10:14:22 CRITICAL Service unreachable
C:\Logs\system.log:201:2026-05-04 10:14:30 CRITICAL Node failover triggered
Recursive Search Across Folders
Combine Get-ChildItem -Recurse with Select-String to search an entire directory tree:
# Search all .log files in all subfolders
Get-ChildItem 'C:\Logs' -Filter '*.log' -Recurse |
Select-String -Pattern 'ORA-\d+' # Oracle error codes
# Search all PowerShell scripts for a function call
Get-ChildItem 'C:\Scripts' -Filter '*.ps1' -Recurse |
Select-String -Pattern 'Send-MailMessage' |
Select-Object Filename, LineNumber, Line
Filename LineNumber Line
-------- ---------- ----
deploy.ps1 45 Send-MailMessage -To '[email protected]' ...
weekly-report.ps1 112 Send-MailMessage -SmtpServer 'mail.corp' ...
Case-Insensitive Matching
By default, Select-String is case-insensitive. To force case sensitivity:
# Default: case-insensitive
Select-String -Path 'C:\Logs\*.log' -Pattern 'error' # Matches ERROR, Error, error
# Case-sensitive with -CaseSensitive
Select-String -Path 'C:\Logs\*.log' -Pattern 'ERROR' -CaseSensitive # Only uppercase ERROR
# Find lines that do NOT match (inverted search)
Select-String -Path 'C:\Logs\app.log' -Pattern 'ERROR' -NotMatch
Show Context Lines with -Context
See lines before and after each match for context — invaluable for log analysis:
# Show 2 lines before and 2 lines after each match
Select-String -Path 'C:\Logs\app.log' -Pattern 'ERROR' -Context 2, 2
# Show 5 lines before only (useful for finding what caused the error)
Select-String -Path 'C:\Logs\app.log' -Pattern 'FATAL' -Context 5, 0
# Format context output clearly
Select-String 'C:\Logs\app.log' -Pattern 'ERROR' -Context 1, 0 |
ForEach-Object {
Write-Output "--- Match in $($_.Filename) line $($_.LineNumber) ---"
$_.Context.PreContext | ForEach-Object { " PRE: $_" }
" MATCH: $($_.Line)"
}
--- Match in app.log line 15 ---
PRE: 2026-05-04 08:15:30 INFO Connecting to database
MATCH: 2026-05-04 08:15:33 ERROR Database connection failed
Export Matches to CSV
Get-ChildItem 'C:\Logs' -Filter '*.log' -Recurse |
Select-String -Pattern 'ERROR|CRITICAL|FATAL' |
Select-Object Filename, LineNumber, Line,
@{ Name='Severity'; Expression={
if ($_.Line -match 'FATAL') { 'FATAL' }
elseif ($_.Line -match 'CRITICAL') { 'CRITICAL' }
else { 'ERROR' }
} } |
Sort-Object Severity, Filename, LineNumber |
Export-Csv 'C:\Reports\log-errors.csv' -NoTypeInformation
Common Errors and Fixes
-
Pattern is regex — escape dots and brackets for literal search:
Select-String -Pattern '192.168.1.1'matches192X168Y1Z1because.is a regex wildcard. For literal text, use-SimpleMatchflag or escape with backslash:'192\.168\.1\.1'. -
Binary files cause encoding errors: Running
Select-Stringagainst.dll,.exe, or image files throws encoding errors. Add-ErrorAction SilentlyContinueor filter file types with-Include '*.log','*.txt'to avoid binary files.
Related Cmdlets / See Also
Wrapping Up
Select-String is the most powerful text search tool in PowerShell. Use wildcards and Get-ChildItem -Recurse for multi-file searches, -Context to see surrounding lines, and export to CSV for incident reports. Remember to use -SimpleMatch or escape special characters when searching for literal text. Your next step: set up a weekly error report script that scans your log folder and emails a CSV of all CRITICAL matches.


