Esteban P.
Esteban P.

Reputation: 2809

-contains or -match several values

I have to filter my results by certain strings and tried to do it with -match and -contains.

-match works if I have just one value to filter, but not with an array.

-contains neither works with one string, nor with a string array.

Why isn't it working with several values? Especially the -contains. Or is there another easy way to solve it?

$Folder = 'C:\Test'

$filterArray =  @('2017-05', '2017-08')
$filter =  '2017-05'

## test with -MATCH

## working with one match string
Get-ChildItem -Path $Folder -Recurse -Include *.txt |
    Where { $_.FullName -match $filter } |
    ForEach-Object { $_.FullName }
## NOT working with match string array - no results
Get-ChildItem -Path $Folder -Recurse -Include *.txt |
    Where { $_.FullName -match $filterArray } |
    ForEach-Object { $_.FullName }

## test with -CONTAINS
## NOT working with one contains string - no results
Get-ChildItem -Path $Folder -Recurse -Include *.txt |
    Where { $_.FullName -contains $filter } |
    ForEach-Object { $_.FullName }
## NOT working with contains string array- no results
Get-ChildItem -Path $Folder -Recurse -Include *.txt |
    Where { $_.FullName -contains $filterArray } |
    ForEach-Object { $_.FullName }

Upvotes: 1

Views: 10600

Answers (2)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174990

Why isn't it working with several values?

Because these operators were designed to test against a single argument, plain and simple.

The ability to match against multiple arguments in a single operation would beg the question: "Does the input need to satisfy all or any of the argument conditions"?


If you want to test for a match against any of an array of regex patterns, you can construct a single pattern from them using a non-capturing group, like so:

$filterPattern = '(?:{0})' -f ($filterArray -join '|')
Get-ChildItem -Path $Folder -Recurse -Include *.txt | Where {$_.FullName -match $filterPattern} | ForEach-Object{ $_.FullName }

You can also drop the Where-Object and ForEach-Object loop completely, since PowerShell 3.0 supports property enumeration:

(Get-ChildItem -Path $Folder -Recurse -Include *.txt).FullName -match $filterPattern

Upvotes: 2

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200503

Using an array as the second operand for the -match or -contains operators doesn't work. There are basically two approaches you could take:

  • Build a regular expression from the array and use that with the -match operator:

    $pattern = @($filterArray | ForEach-Object {[regex]::Escape($_)}) -join '|'
    ... | Where-Object { $_.FullName -match $pattern }
    

This is the preferred approach.

  • Use a nested Where-Object filter and the String.Contains() method:

    ... | Where-Object {
        $f = $_.FullName
        $filterArray | Where-Object { $f.Contains($_) }
    }
    

Upvotes: 4

Related Questions