Reputation: 449
I'm using the below script to copy files from an install directory, and then remove all files except XML files. I'd like to also exclude .log
and .txt
files from deletion. How do I format this to accomplish that?
Bonus points if there is a way to download ONLY XML/LOG/TXT files, including the folder structure, without having to go back and delete extra stuff.
Copy-Item -Path $cis_wild -Destination $target_cis -Container -Recurse
Get-ChildItem -Path $target_cis -Recurse -File | Where {($_.Extension -ne ".xml")} | Remove-Item
Upvotes: 2
Views: 2301
Reputation: 439597
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:
-Exclude
, by contrast, mostly works as expected: it applies the exclusion patterns on each level of the directory subtree hierarchy.
See this answer for a detailed discussion, including a problem with how -Destination
arguments are interpreted.
Upvotes: 4