Reputation: 51
So, i've been scratching my head for a while now and can't seem to figure it out.
I want to delete files and folders older than 'x' days <-- this works fine I want to delete empty directories left behind <-- this works fine as well
I also want to have some exceptions: filenames and foldernames. The filename exception works fine, but folders don't. There is something strange though. If i put only 1 name in the array of folders i don't want to delete, it works just fine. But if i put multiple in, it suddenly doesn't work anymore?
I have the idea it might be something simple i'm completely missing
$limit = (Get-Date).AddDays(-120)
$path = "C:\Users\user\Documents\files"
$ExcludedFileNames = @("*file1*", "*file2*")
$ExcludedFolders = @("*folder1*", "*folder2*")
# Delete files older than the $limit.
Get-ChildItem -Path $path -Recurse -Force -exclude $ExcludedFileNames |
Where-Object {($_.FullName -notlike $ExcludedFolders) -and (!$_.PSIsContainer) -and ($_.LastWriteTime -lt $limit) } |
Remove-Item -Force
# Delete any empty directories left behind after deleting the old files.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } | Remove-Item -Force -Recurse
Instead of $.FullName i tried $.Name Instead of -notlike i tried -notin I also tried removing the array and put the variables after where-object
I also tried to copy other code from lots of posts but didn't seem to help.
Upvotes: 2
Views: 278
Reputation: 61093
I would use wildcards on the file names to use with the -Exclude
parameter, and create a regex string for the foldernames to exclude you can use in the Where-Object
clause.
Something like this:
$limit = (Get-Date).AddDays(-120).Date # set to midnight instead of the current time
$path = 'C:\Users\user\Documents\files'
$ExcludedFileNames = '*file1*', '*file2*' # wildcards for the Exclude parameter
$ExcludedFolders = 'folder1','folder2' # can be a partial name, do not use wildcards here
# create a regex string for the folder names to exclude
# each item will be Regex Escaped and joined together with the OR symbol '|'
$FoldersToSkip = ($ExcludedFolders | ForEach-Object { [Regex]::Escape($_) }) -join '|'
# Delete files older than the $limit.
Get-ChildItem -Path $path -File -Recurse -Force -Exclude $ExcludedFileNames |
Where-Object {($_.DirectoryName -notmatch $FoldersToSkip) -and ($_.LastWriteTime -lt $limit) } |
Remove-Item -Force
# Delete any empty directories left behind after deleting the old files.
(Get-ChildItem -Path $path -Recurse -Directory -Force).FullName |
Where-Object { !( Get-ChildItem -Path $_ | Select-Object -First 1 ) } |
Sort-Object -Property Length -Descending |
Remove-Item -Force
Upvotes: 3
Reputation: 174545
The problem is that -notlike
expects a single string as it's right-hand side operand, and so the $ExcludedFolders
variable is coerced into the stringvalue "*folder1* *folder2*"
.
The comparison 'C:\some\path\to\a\folder1\with\a\file.exe' -notlike '*folder1* *folder2*'
obviously fails.
You can solve this by using the -notmatch
regex operator instead:
$ExcludedFolders = @('folder1', 'folder2') # note that we no longer need the wildcards
# later
... |Where-Object {$_.FullName -notmatch ($ExcludedFolders.ForEach{[regex]::Escape($_)} -join '|') -and (-not $_.PsIsContainer) -and $_.LastWriteTime -lt $limit}
The |
is the alternation operator in regex, effectively functioning as an OR
Upvotes: 4