I am writing a PowerShell script in version 5.1 on Windows 10 that gets certain pieces of information about a local system ( and eventually its subnets ) and outputs them in
tl; dr:
Force synchronous output to the console by using a formatting cmdlet explicitly:
getUsersAndGroups | Out-Host
getRunningProcesses | Out-Host
Note: You can alternatively use one of the Format-*
cmdlets, which also forces synchronous output; e.g., getUsersAndGroups | Format-Table
.
Note that this is primarily a display problem, and you do not need this workaround for capturing output in a file or passing it on through the pipeline.
However, sending to Out-Host
means that the commands' output can no longer be captured or redirected; see this answer for a - suboptimal - workaround.
It's helpful to demonstrate the problem with an MCVE (Minimal, Complete, and Verifiable Example):
Write-Host "-- before"
[pscustomobject] @{ one = 1; two = 2; three = 3 }
Write-Host "-- after"
In PSv5+, this yields:
-- before
-- after
one two three
--- --- -----
1 2 3
What happened?
The Write-Host
calls produced output synchronously.
Write-Host
bypasses the normal success output stream and (in effect) writes directly to the console - mostly, even though there are legitimate uses, Write-Host should be avoided.The implicit output - from not capturing the output from statement [pscustomobject] @{ one = 1; two = 2; three = 3 }
- was unexpectedly not synchronous:
Write-Host
call.This helpful answer explains why that happens; in short:
Implicit output is formatted based on the type of objects being output; in the case at hand, Format-Table
is implicitly used.
In Psv5+, implicitly applied Format-Table
now waits up to 300 msecs. in order to determine suitable column widths.
To test whether a given type with full name <FullTypeName>
has table-formatting data associated with it, you can use the following command:
# Outputs $true, if <FullTypeName> has predefined table-formatting data.
Get-FormatData <FullTypeName> -PowerShellVersion $PSVersionTable.PSVersion |
Where-Object {
$_.FormatViewDefinition.Control.ForEach('GetType') -contains [System.Management.Automation.TableControl]
}
Unfortunately, that means that subsequent commands execute inside that time window and may produce unrelated output (via pipeline-bypassing output commands such as Write-Host
) or prompt for user input before Format-Table
output starts.
The problematic behavior is discussed in this GitHub issue; while there's still hope for a solution, there has been no activity in a long time.
Note: This answer originally incorrectly "blamed" the PSv5+ 300 msec. delay for potentially surprising standard output formatting behavior (namely that the first object sent to a pipeline determines the display format for all objects in the pipeline, if table formatting is applied - see this answer).