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!"
}
>Solution :
-
$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 results in implicitly
Format-Table
-formatted display representations (for custom objects that have no predefined formatting data), the subsequentRead-Host
andWrite-Host
statements – surprisingly – print 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. -
The – suboptimal – workaround is to force pipeline output to print synchronously to the host (display), using
Out-Host
. -
See this answer for details.
-