I'm a powershell noob. How come the following code is also outputing the table at the end after the "File to Delete" loop?
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
# use partial hashes for files larger than 100KB:
# see documentation at: https://powershell.one/tricks/filesystem/finding-duplicate-files#finding-duplicate-files-fast
$result = Find-PSOneDuplicateFileFast -Path '\\READYNAS\Pictures\2020\10' #-Debug -Verbose
$stopwatch.Stop()
# output duplicates
$allFilesToDelete = @(foreach($key in $result.Keys)
{
#filters out the LAST item in the array of duplicates, because a file name of xxxx (0) comes before one without the (0)
$filesToDelete = $result[$key][0..($result[$key].count - 2)]
#add each remaining duplicate file to table
foreach($file in $filesToDelete)
{
$file |
Add-Member -MemberType NoteProperty -Name Hash -Value $key -PassThru |
Select-Object Hash, Length, FullName
}
}
)
$allFilesToDelete | Format-Table -GroupBy Hash -Property FullName | Out-String | Write-Host
$allFilesToDelete | Sort-Object -Property FullName -OutVariable allFilesToDelete
$allFilesToDelete | Format-Table -Property FullName | Out-String | Write-Host
$confirmation = Read-Host "Are you Sure You Want To Delete $($allFilesToDelete.count) files? (y/n)"
if ($confirmation -eq 'y') {
$i = 0
foreach($fileToDelete in $allFilesToDelete)
{
$i
Write-Host "$i File to Delete: $($fileToDelete.FullName)"
#Remove-Item $file.FullName -Force -Verbose 4>&1 | % { $x = $_; Write-Host "Deleted file ($i) $x" }
}
} else {
Write-Host "User chose NOT to delete files!"
}
CodePudding user response:
$allFilesToDelete | Sort-Object -Property FullName -OutVariable allFilesToDelete
produces output (the input objects in the requested sort order), and since you're not capturing or redirecting it, it prints to the host (display, terminal) by default.It seems your intent is to sort the objects stored in
$allFilesToDelete
, which your command does, but it also produces output (the common-OutVariable
parameter does not affect a cmdlet's output behavior, it simply also stores the output objects in the given variable); you could simply assign the output back to the original variable, which wouldn't produce any output:$allFilesToDelete = $allFilesToDelete | Sort-Object -Property FullName
In cases where actively suppressing (discarding) output is needed,
$null = ...
is the simplest solution:- See this answer for details and alternatives.
- Also see this blog post, which you found yourself.
Because the output resulted in implicitly
Format-Table
-formatted display representations (for custom objects that have no predefined formatting data), the subsequentRead-Host
andWrite-Host
statements - surprisingly - printed first.The reason is that this implicit use of
Format-Table
results in asynchronous behavior: output objects are collected for 300 msecs. in an effort to determine suitable column widths, and during that period output to other output streams may print.The - suboptimal - workaround is to force pipeline output to print synchronously to the host (display), using
Out-Host
.See this answer for details.