Is there any way to condense multiple Where-Object conditions in PowerShell?

717 views Asked by At

Novice scripter here and I have a script that connects to multiple file servers and recurses through directories on them looking for files over 90 days old. All that works great.

I'm using Get-ChildItem -include and -exclude to filter the files I want to report on but I also need to filter out certain directories and get-childitem can't filter directories so I'm piping the results over to a Where-Object that then compares the $_.FullName property to strings I want to exclude.

My problem is that I'm having to adjust the directory names I'm filtering for on a regular basis depending on what clients name their files and managing the script is getting a little out of hand as I have to keep adding -and ($_.FullName -notMatch "BACKUPS") conditions to the get-childitem line.

Here's my relevant code:

$Exclusions = ('*M.vbk','*W.vbk','*Y.vbk')
$Files = Get-ChildItem $TargetFolder -include ('*.vib','*.vbk','*.vbm','*.vrb') -Exclude $Exclusions -Recurse -File | 
         Where {($_.LastWriteTime -le $LastWrite) -and 
             ($_.FullName -notMatch "BACKUPS") -and 
             ($_.FullName -notMatch "Justin") -and 
             ($_.FullName -notMatch "Monthly") -and 
             ($_.FullName -notMatch "Template") -and 
             ($_.FullName -notMatch "JIMMY") -and 
             ($_.FullName -notMatch "ISAAC")}

I set up the $Exclusions variable to use in Get-ChildItem so that I have a single variable to adjust as needed. Is there a way to condense all the individual Where ($.FullName -notMatch "JIMMY") entries to just use one variable like... Where ($.FullName -notMatch $DirectoryListVariable)?

Basically I just need to make this easier to manage and change if that's possible. If not then I can just keep adding new lines but I'm hoping there is a better way.

Thanks for your time!

1

There are 1 answers

1
mklement0 On

Use regex alternation (|) to match any one of multiple patterns:

# Array of name substrings to exclude.
$namesToExclude = 'BACKUPS', 'Monthly', 'Justin', 'Template', 'JIMMY', 'ISAAC' # , ...

# ...
... | Where-Object { 
  $_.LastWriteTime -le $LastWrite -and 
  $_.FullName -notmatch ($namesToExclude -join '|')
}
  • For case-sensitive matching, use -cnotmatch

  • As an alternative to defining an array of patterns to then -join with | to form a single string ('BACKUPS|Monthly|...'), you may choose to define your names as part of such a single string to begin with.

    • Do note that the resulting string must be a valid regex; that is, the individual names are interpreted as regexes (subexpressions) too.

    • If that is undesired (note that it isn't a problem here, because the specific sample names are also treated literally as regexes), you can escape them with [regex]::Escape().

  • Finally, note that -match and its variant perform substring (subexpression) matching; to match input strings in full, you need to anchor the expressions, namely with ^ (start of the string) and $ (end of the string); e.g.
    'food' -match 'oo' is $true, but 'food' -match '^oo$' is not ('oo' -match '^oo$' is).