1

I am wanting to filter through a list of folders that include a certain criteria while excluding another set of criteria in PowerShell.

The code below is what is currently being played around with that has had partial succession; -Exclude seems to exclude folders that contain *EDS* in the name but not *eng*. Below is a sample output of what is still being included:

C:\Users\USERNAME\Box\CTRL Active Projects\project1\project1_OPS\06-Software\04-Database Backups\01-Record Backup
C:\Users\USERNAME\Box\CTRL Active Projects\project1\project1_OPS\06-Software\04-Database Backups
C:\Users\USERNAME\Box\CTRL Active Projects\project1\project1_OPS\01-Eng\03-Submittals WIP\Backups

The -Exclude *eng*, *EDS* might eventually be converted over to a variable/named arraylist.

# Find sub-folder within job folder
$DatabaseFolder = (Get-ChildItem -Path $JobFolder -Filter "*Backup*" -Exclude *eng*, *EDS* -Recurse -Directory).Fullname | Sort-Object -Descending -Property LastWriteTime
Write-Output $DatabaseFolder

The $JobFolder returns the path to search the sub directories:

C:\Users\USERNAME\Box\CTRL Active Projects\project1\

Some other background info: PowerShell 5.1 is being used as Administrator, Windows 10 OS

Could someone help me understand why the code is still including some of the excluded parameters?

2
  • I can't replicate this issue. Did this just start happening? Also, when piping to your Sort-Object, you're not really sorting by the LastWriteTime property since you're only outputting the fullname to the pipeline. Commented Feb 1, 2022 at 18:57
  • @AbrahamZinala - Three items: (1) The issue is that it is included the 3rd full path C:\Users\USERNAME\Box\CTRL Active Projects\project1\project1_OPS\01-Eng\03-Submittals WIP\Backups even though the -Exclude is listing *eng*, *EDS* (2) The other option instead of using -Filter was to see how -Include works with -Exclude but so far the results have been the same. (3) The goal with Sort-Object was to capture and list in order an array of folders that included the the words 'backup' in the name somewhere and exclude 'EDS' and 'ENG' in its name. Commented Feb 1, 2022 at 19:58

2 Answers 2

3
  • Both -Filter and -Include / -Exclude only ever operate on the last path component - i.e. an input file-system item's name (.Name property).

  • When -Exclude is combined with -Recurse, only the matching items themselves are excluded, not also their subtrees. That is, the contents (child items) of an excluded directory are still enumerated (unless their names too happen to match the exclusion pattern).

Therefore, ...\01-Eng\03-Submittals WIP\Backups, for instance, was still included in your output: the *eng* -Exclude filter excluded ...\01-Eng itself, but kept enumerating its subdirectories.

As of PowerShell (Core) 7.2.1, there is no direct way to exclude directory subtrees by wildcard patterns from a Get-ChildItem -Recurse enumeration; GitHub issue #15159 proposes adding this functionality.


Therefore, you'll have to perform your exclusions by post-filtering with a Where-Object call that matches against the full path (.FullName property):

Get-ChildItem -Recurse -Directory -Path $JobFolder -Filter *Backup* |
  Where-Object FullName -notmatch 'eng|EDS'

Note: For brevity, -notmatch with a regex that uses alternation (|) is used to match multiple substrings.

To use wildcard expressions, you'd have to use the -notlike operator multiple times, once for each pattern (which would also require you to use a script block argument, with explicit use of $_, i.e. you then couldn't use the simplified syntax shown above; in other words:
Where-Object { $_.FullName -notlike '*eng*' -and $_.FullName -notlike '*EDS*' }).

Sign up to request clarification or add additional context in comments.

2 Comments

mklement0, another parameter that was added to some of the folder searches were using a -Depth for the recursion. Even though FullName will have the full path searched at, could -Depth also be used to limit which folders are returned if character matching is known to a certain depth? i.e. -Depth 1. Thank you for the response; immensely informative!
Glad to hear it was helpful, @Screamcheese; my pleasure. Yes, -Depth can be used to limit how many levels of the subtree hierarchy are enumerated (0 only enumerates immediate children, 1 also enumerates children of children, ...), and -Filter and -Include / -Exclude are then applied to that constrained enumeration.
0

I don't see anything in the documentation about using Filter and Exclude:

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7.2

However, since it's not working as you intended, you can always manually perform the exclude:

gci -recurse -directory | ? { $_.Name -notlike "*eng*" -and $_.Name -notlike "*EDS*" }

1 Comment

thepip3r, a couple things: (1) an alternative approach would be to use -Include with -Exclude somehow, (2) manually performing the exclude with your example could become a little more tedious and error prone if a list of elements/patterns needs to be updated or scalable, so another desired approach would be to having an arraylist to be a little more dynamic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.