'How to specify multiple file types to exclude when deleting files in Powershell
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
Solution 1:[1]
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/-Excludework as expected withGet-ChildItem -Recurse, they don't without it, and it's not easy to remember this fact - see the bottom section.Combining
-Include/-ExcludewithGet-ChildItem -Recurseis 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
-Recursefor recursive traversal withGet-ChildItemthat-Excludeand-Includework as one would expect; without-Recurse, these parameters exhibit counter-intuitive behavior - see this answer.With
Copy-Item, even-Recursewouldn't make-Includework, though-Excludewould mostly work as expected:That is, while you should be able to use
-Includewith multiple wildcard patterns for inclusionary matching directly withCopy-Item -Recursein order to limit what is copied to begin with, it doesn't work.-Includeis 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
-Destinationarguments are interpreted.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
