-Filter
only accepts a single pattern.
Use -Include
and -Exclude
instead[1], both of which accept multiple patterns.
# Two inclusion patterns
Get-ChildItem -Recurse -Path $sourcePathPDF -Include *.pdf, *sold*
# One inclusion, one exclusion pattern.
Get-ChildItem -Recurse -Path $sourcePathPDF -Include *.pdf -Exclude *Sold*
Note:
As of PowerShell 7.2, -Include
and -Exclude
are hampered by performance problems, as Mathias R. Jessen notes, due to their inefficient implementation (see GitHub issue #8662), so the Where-Object
-based solution discussed below may be called for not just for more complex matching logic, but for performance alone.
-Include
and -Exclude
use PowerShell's wildcard expressions, which have more features and lack the legacy quirks of the platform-native patterns that -Filter
supports - see this answer for more information.
- The upside of using
-Filter
is that its much faster than -Include
/ -Exclude
, because -Filter
filters _at the source, whereas -Include
/ -Exclude
filters are applied after the fact, by PowerShell, after all items have been retrieved first.
Without -Recurse
, -Include
and -Exclude
do not work as expected - use Get-Item * -Include/-Exclude ...
instead - see this answer.
For more sophisticated pattern matching and/or better performance, pipe to a Where-Object
call in whose script block you can use the wildcard-based -like
operator, as Mathias recommends; alternatively, for even more flexible matching, you can use the regex-based -match
operator. To adapt Mathias' -like
-based Where-Object
solution from the comment:
Get-ChildItem -Recurse -Path $sourcePathPDF |
Where-Object { $_.Name -like '*.pdf' -and $_.Name -notlike '*Sold*' }
For (currently) best performance you can pre-filter with -Filter
:
Get-ChildItem -Recurse -Path $sourcePathPDF -Filter *.pdf |
Where-Object { $_.Name -notlike '*Sold*' }
As for what you tried:
-Filter
, -Include
, and -Exclude
are string-typed - there is no support for passing script blocks ({ ... }
with arbitrary expression to them.
- While pipeline-binding parameters may accept script blocks, in order to supply parameter values dynamically, based on the input object at hand (a feature known as delay-bind script blocks), neither of these parameters support such binding, so passing script blocks doesn't apply.
What actually happened in your attempt is that the stringified version of script block {-filter '*.pdf' -and '*Sold*'}
- which is its verbatim content (excluding {
and }
) - was positionally bound to the -Filter
parameter.
- That is, you effectively passed
-Filter "-filter '*.pdf' -and '*Sold*'"
, which predictably didn't match any files, because verbatim -filter '*.pdf' -and '*Sold*'
was used as the pattern.
[1] Note that you may even combine -Filter
with -Include
/ -Exclude
, in which case the -Filter
argument is applied first, at the source. Because of how -Include
and -Exclude
currently work, this is only works meaningfully if the input path ends in \*
or -Recurse
is used - see this answer.