Reputation: 31
I have a folder with .jpg files in it. I associate these with products in an access database. One of the sources for products provides these .jpg files but they do not allow you to easily download only the pictures that you currently use. Therefore I have found a PowerShell Script to delete the files that I do not need.
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
dir -rec M:\PhotoDirectory\PhotoFolder | Where-Object {$exclusions -notcontains $_.name } | Remove-Item
Credit to @x0n Powershell script to delete files not specified in a list
And it works great! but the problem is it takes forever and I have over 180,000 items to search through and delete. So I wanted to make a progress bar that would let me know how far I had gone through the process.
So after a little bit of searching I found an article called "using the progress bar"
The problem is I don't know how to mash the two together, However I have made an attempt here:
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
1..100 | foreach-object {
Write-Progress -Activity "Deleting Files" -Status "$_ %" -Id 1 -PercentComplete $_ -CurrentOperation "Deleting File $_"
dir -rec M:\PhotoDirectory\PhotoFolder | Where-Object {$exclusions -notcontains $_.name } | Remove-Item
}
However that seems to take even longer than the original script did, I don't know exactly how it is working, and I am testing it when I only need to remove 10-15 files.
It is likely there is something really basic I am missing But I would really appreciate some help understanding this.
Here I have added a screenshot:
Upvotes: 3
Views: 3330
Reputation: 174485
However that seems to take even longer than the original script did
That's because you're attempting to enumerate, filter and delete the files 100 times - which is obviously unnecessary.
What you want to do is calculate how far in the process of deleting the files you are, and then use that as a basis for the percentage you pass to Write-Progress
. The easiest way to keep count is probably to use a regular for
loop:
Note: these first two examples are very generic, go to the bottom for an example that takes your volume (~180.000 files) into account.
# Grab all the files you need to delete
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
$filesToDelete = Get-ChildItem M:\PhotoDirectory\PhotoFolder -Recurse | Where-Object {$exclusions -notcontains $_.Name }
for($i = 0; $i -lt $filesToDelete.Count; $i++){
# calculate progress percentage
$percentage = ($i + 1) / $filesToDelete.Count * 100
Write-Progress -Activity "Deleting Files" -Status "Deleting File #$($i+1)/$($filesToDelete.Count)" -PercentComplete $percentage
# delete file
$filesToDelete[$i] |Remove-Item
}
# All done
Write-Progress -Activity "Deleting Files" -Completed
Another characteristic you might want to use to indicate a percentage is the relative volume (total number of bytes) removed. We can do this by simply keeping track of how many bytes we need to remove total, and how many we've removed so far:
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
$filesToDelete = Get-ChildItem M:\PhotoDirectory\PhotoFolder -Recurse | Where-Object {$exclusions -notcontains $_.Name }
$TotalSize = ($filesToDelete |Measure-Object -Property Length -Sum).Sum
$BytesRemoved = 0
foreach($file in $filesToDelete){
$percentage = $BytesRemoved / $TotalSize * 100
Write-Progress -Activity "Deleting Files" -Status "Deleted $BytesRemoved/$TotalSize bytes" -PercentComplete $percentage
$file |Remove-Item
$BytesRemoved += $file.Length
}
Write-Progress -Activity "Deleting Files" -Completed
As @MatthewWetmore points out, invoking Write-Progress
every time you delete a file will of course incur some overhead. And with 180.000 files, you're probably not that interested in having the UI update when the progress goes from 3.56325% to 3.56331%
What you could do is use the for
loop to count in increments of 1% of the entire set of items, and then remove a whole range of files on each iteration:
[int]$hundredthStep = $filesToDelete.Count / 100
for($i = 0; $i -lt $filesToDelete.Count; $i += $hundredthStep){
# calculate progress percentage
$percentage = ($i + 1) / $filesToDelete.Count * 100
Write-Progress -Activity "Deleting Files" -Status "Deleting File up to #$($i+1)/$($filesToDelete.Count)" -PercentComplete $percentage
# delete file
$filesToDelete[$i..($i + $hundredthStep - 1)] |Remove-Item
}
# All done
Write-Progress -Activity "Deleting Files" -Completed
Upvotes: 6
Reputation: 23355
You want to do something like this (beware this is untested so i've put -whatif
on the remove cmdlet which you should remove when you're happy it's working correctly):
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
$files = dir -rec M:\PhotoDirectory\PhotoFolder | Where-Object {$exclusions -notcontains $_.name }
$files | foreach-object {
$num += 1
Write-Progress -Activity "Deleting Files" -Status "$_ %" -Id 1 -PercentComplete (($num / $files.count) * 100) -CurrentOperation "Deleting File $($_.name)"
$_ | Remove-Item -WhatIf
}
Upvotes: 2