Home > Enterprise >  Why Powershell outputting this table?
Why Powershell outputting this table?

Time:12-29

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!"
}

enter image description here

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:

  • Because the output resulted in implicitly Format-Table-formatted display representations (for custom objects that have no predefined formatting data), the subsequent Read-Host and Write-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.

  • Related