Use the -Exclude
parameter, which allows you to specify an array of exclusion wildcard patterns - but see the caveats below:
Get-ChildItem -Exclude *.xml, *.txt, *.log -Path $target_cis -Recurse -File |
Remove-Item -WhatIf
Note: The -WhatIf
common parameter in the command above previews the operation. Remove -WhatIf
once you're sure the operation will do what you want.
Post-filtering solution, building on your own attempt:
While it is generally preferable to solve a problem directly with a given cmdlet's parameter - both for concision and performance - as of PowerShell 7.2.2, there are good reasons to perform the filtering separately, applying it after Get-ChildItem
has returned its (unfiltered) results (which is what you attempted):
While -Include
/ -Exclude
work as expected with Get-ChildItem -Recurse
, they don't without it, and it's not easy to remember this fact - see the bottom section.
Combining -Include
/ -Exclude
with Get-ChildItem -Recurse
is unexpectedly slow - even slower than a post-filtering solution: see GitHub issue #8662
Get-ChildItem -Path $target_cis -Recurse -File |
Where-Object { $_.Extension -notin '.xml', '.txt', '.log' } |
Remove-Item -WhatIf
That is, switching from the -ne
operator in your attempt ($_.Extension -ne ".xml"
) to the
-notin
operator allows placing an array of strings on the RHS to test the the LHS string against:
$_.Extension -notin '.xml', '.txt', '.log'
returns $true
if the value of $_.Extension
is not present in the RHS array (using implicit -eq
testing against each element).
Caveats as of PowerShell 7.2.2:
It is solely because your commands use -Recurse
for recursive traversal with Get-ChildItem
that -Exclude
and -Include
work as one would expect; without -Recurse
, these parameters exhibit counter-intuitive behavior - see this answer.
With Copy-Item
, even -Recurse
wouldn't make -Include
work, though -Exclude
would mostly work as expected:
That is, while you should be able to use -Include
with multiple wildcard patterns for inclusionary matching directly with Copy-Item -Recurse
in order to limit what is copied to begin with, it doesn't work.
-Include
is mistakenly applied to the immediate target directory and only to it:
- If none of the specified patterns match its name, nothing is copied.
- If any specified pattern does match its name, the whole directory subtree is copied without filtering.
-Exclude
, by contrast, mostly works as expected: it applies the exclusion patterns on each level of the directory subtree hierarchy.
- If any exclusion pattern happens to match the name of the immediate target directory, nothing is copied.
See this answer for a detailed discussion, including a problem with how -Destination
arguments are interpreted.