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?
CodePudding user response:
Both
-Filterand-Include/-Excludeonly ever operate on the last path component - i.e. an input file-system item's name (.Nameproperty).When
-Excludeis 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*' }).
CodePudding user response:
I don't see anything in the documentation about using Filter and Exclude:
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*" }
