Thomas
Thomas

Reputation: 451

How to use PowerShell select-string to find more than one pattern in a file?

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

Answers (3)

js2010
js2010

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

Rynant
Rynant

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

Emperor XLII
Emperor XLII

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

Related Questions