Why different results for Invoke-Command and Get-Volume?

I’m trying to learn PowerShell and started with a “simple” project, getting free disk space from a list of specific servers.

  1. I get different results, mainly the sorting by “%Free”, with the same command line depending on if I specify the FQDNs on the command line after Invoke-Command -ComputerName or if I pull the FQDNs from a text file with Get-Content. To troubleshoot this, I put both versions in the same script to compare the results. That lead to an even more mysterious issue.
  2. The first Invoke-Command doesn’t seem to run until the second command runs even though the commands are separated by different Write-Host messages, and a Start-Sleep 60 command. There should be some sort of output from the first Invoke-Command under the “Servers specified in the command line:”.

Each line works properly, if I just cut and paste it into PowerShell.

Currently output looks like this:

Servers specified in the command line:



Servers specified in a file:
PSComputerName             DriveLetter %Free  
--------------             ----------- -----  
VRT-SMP-002-WAT.tst.com           C 60.13 %
VRT-EXC-005-WAT.tst.com           C 76.94 %
VRT-RDS-001-WMT.tst.com           C 78.33 %
VRT-SMP-002-WAT.tst.com           D 97.90 %
VRT-RDS-001-WMT.tst.com           D 99.79 %
VRT-EXC-005-WAT.tst.com           D 99.81 %
VRT-EXC-005-WAT.tst.com           C 76.94 %
VRT-EXC-005-WAT.tst.com           D 99.81 %
VRT-RDS-001-WMT.tst.com           C 78.33 %
VRT-RDS-001-WMT.tst.com           D 99.79 %
VRT-SMP-002-WAT.tst.com           C 60.13 %
VRT-SMP-002-WAT.tst.com           D 97.90 %
Cls
Write-Host Servers specified in the command line:
Invoke-Command -ComputerName VRT-EXC-005-WAT.tst.com, VRT-RDS-001-WMT.tst.com, VRT-SMP-002-WAT.tst.com {Get-Volume -DriveLetter C,D} |Select PSComputerName, DriveLetter, @{L='%Free';E={($_.sizeremaining/$_.size).ToString("P")}} |Sort %Free
Write-Host "`n"
Start-Sleep -Seconds 60

Write-Host Servers specified in a file:
$serverlist = Get-Content D:\Scripts\John\New\DiskSpace\TestServers.txt

ForEach ($name in $serverlist)
{
    Invoke-Command -ComputerName $name {Get-Volume -DriveLetter C,D} |Select PSComputerName, DriveLetter, @{L='%Free';E={($_.sizeremaining/$_.size).ToString("P")}} |Sort %Free  
}

TestServers.txt contents:

VRT-EXC-005-WAT.tst.com
VRT-RDS-001-WMT.tst.com
VRT-SMP-002-WAT.tst.com
$PSVersionTable
Name                           Value                                                                                                                             
----                           -----                                                                                                                             
PSVersion                      5.1.14393.5127                                                                                                                    
PSEdition                      Desktop                                                                                                                           
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                                           
BuildVersion                   10.0.14393.5127                                                                                                                   
CLRVersion                     4.0.30319.42000                                                                                                                   
WSManStackVersion              3.0                                                                                                                               
PSRemotingProtocolVersion      2.3                                                                                                                               
SerializationVersion           1.1.0.1

Write-Host goes directly to the host where objects can be “stored” for a bit. This is not exactly what’s getting you here, as it’s clearly the Sort-Object command. This cmdlet can’t sort the objects until it has them all. The Host commands have already been processed by the compiler so of course it beats your sorted output. No amount of sleeping will fix this. Add Out-Host/Out-Default after the output of object to force output to the host at that time.

Please note that Write-Host usually can be replaced by Write-Verbose, Write-Information, or Write-Debug. If you mix in read/write-host and output is showing up out of place, can almost guarantee it’s because of the aforementioned “issues”.

Also, you are really hurting your performance hitting one machine at a time in your second example. Invoke-Command can take a list of computers just like your first example and run them all at once (depending on how many and the -ThrottleLimit parameter)

Cls
Write-Host Servers specified in the command line:
$serverlist = 'VRT-EXC-005-WAT.tst.com', 'VRT-RDS-001-WMT.tst.com', 'VRT-SMP-002-WAT.tst.com'

Invoke-Command -ComputerName $serverlist {
    Get-Volume -DriveLetter C,D} |
        Select-Object PSComputerName,
                      DriveLetter,
                      @{L='%Free';E={($_.sizeremaining/$_.size).ToString("P")}
} | Sort-Object %Free | Out-Host

Write-Host "`n"

Write-Host Servers specified in a file:
$serverlist = Get-Content D:\Scripts\John\New\DiskSpace\TestServers.txt

Invoke-Command -ComputerName $serverlist {
    Get-Volume -DriveLetter C,D} |
        Select-Object PSComputerName,
                      DriveLetter,
                      @{L='%Free';E={($_.sizeremaining/$_.size).ToString("P")}
} | Sort-Object %Free | Out-Host
2 Likes

Thank you.

I can understand why Write-Host will come back sooner than an Invoke-Command across multiple distributed servers. I just thought it would do them in order from top to bottom.

In my second example what makes it slower, reading from the .txt file?

I don’t know what you mean by slower. You mean out of order? That is because when the script is parsed (when you run it) all the host commands go directly to the host. Your other commands require processing. Even without the sort, powershell can still take a few seconds to output what you see. That is taking the rich objects and applying special formatting to them for your eyes. The host commands go directly to this formatting system. That’s why adding Out-Host (it logically comes before your second write-host, so it has to be processed before it) corrects the host output order. Out-Default also works because it just uses the default which is usually Out-Host.

There is probably some technical mistake with my explanation, and you can find more technically sound answers on stackoverflow. Search for “command output out of order powershell” and you’ll surely find some gems. A user by the name of MKlement0 has provided some very in depth answers on this topic.

2 Likes