Reputation: 451
I would like to search for more than one string in the files in a directory, however using "select-string -pattern" didn't help. Could anyone show me how to do it?
Example: Search all files in C:\Logs that contain the words "VendorEnquiry" and "Failed", and with a Logtime about 11:30 am. Structure of files may differ (e.g. different tag names, etc):
... <methodException>VendorEnquiry</methodException> ...
... <logTime>13/10/2010T11:30:04 am</logTime> ...
... <status>Failed</status> ...
... <serviceMethodException>VendorEnquiry</serviceMethodException> ...
... <logTime>13/10/2010</logTime> ...
... <serviceStatus>Failed</serviceStatus> ...
Thanks.
Upvotes: 45
Views: 174471
Reputation: 27428
You can specify multiple patterns in an array:
Select-String -Pattern 'VendorEnquiry', 'Failed' -LiteralPath "$Env:SystemDrive\Logs"
This works with -NotMatch
as well:
Select-String -NotMatch 'VendorEnquiry', 'Failed' -LiteralPath "$Env:SystemDrive\Logs"
Upvotes: 31
Reputation: 24283
If you want to match the two words in either order, use:
gci C:\Logs| select-string -pattern '(VendorEnquiry.*Failed)|(Failed.*VendorEnquiry)'
If Failed always comes after VendorEnquiry on the line, just use:
gci C:\Logs| select-string -pattern '(VendorEnquiry.*Failed)'
Upvotes: 45
Reputation: 13432
To search for multiple matches in each file, we can sequence several Select-String calls:
Get-ChildItem C:\Logs |
where { $_ | Select-String -Pattern 'VendorEnquiry' } |
where { $_ | Select-String -Pattern 'Failed' } |
...
At each step, files that do not contain the current pattern will be filtered out, ensuring that the final list of files contains all of the search terms.
Rather than writing out each Select-String call manually, we can simplify this with a filter to match multiple patterns:
filter MultiSelect-String( [string[]]$Patterns ) {
# Check the current item against all patterns.
foreach( $Pattern in $Patterns ) {
# If one of the patterns does not match, skip the item.
$matched = @($_ | Select-String -Pattern $Pattern)
if( -not $matched ) {
return
}
}
# If all patterns matched, pass the item through.
$_
}
Get-ChildItem C:\Logs | MultiSelect-String 'VendorEnquiry','Failed',...
Now, to satisfy the "Logtime about 11:30 am" part of the example would require finding the log time corresponding to each failure entry. How to do this is highly dependent on the actual structure of the files, but testing for "about" is relatively simple:
function AboutTime( [DateTime]$time, [DateTime]$target, [TimeSpan]$epsilon ) {
$time -le ($target + $epsilon) -and $time -ge ($target - $epsilon)
}
PS> $epsilon = [TimeSpan]::FromMinutes(5)
PS> $target = [DateTime]'11:30am'
PS> AboutTime '11:00am' $target $epsilon
False
PS> AboutTime '11:28am' $target $epsilon
True
PS> AboutTime '11:35am' $target $epsilon
True
Upvotes: 35