Output, formatting and Write-Host

PowerShell · Practical · 10 min

Mixing up output and display is the top reason PowerShell functions return garbage or print nothing.

PowerShell separates output (objects sent down the pipeline, which callers can capture) from display (what the host shows you). Anything not captured is output; Write-Output is the explicit form but rarely needed.

For messages, use the cmdlet for the purpose, because each writes to its own stream, not to the output:

  • Write-Verbose (shown with -Verbose), Write-Debug, Write-Warning, Write-Error,
  • Write-Information and Write-Host for user-facing text; Write-Host can add colour.

That way $result = My-Function captures only data, not chatter.

Format-Table, Format-List and Format-Wide turn objects into formatting instructions for display. Use them only at the end of a pipeline: after Format-Table you no longer have the original objects, so sorting, exporting or reading properties breaks. To get text, use Out-String; to write to a file, Out-File or Set-Content; to save data, prefer Export-Csv or ConvertTo-Json.

The -f format operator builds strings: '{0} is {1:N1} GB' -f $name, $size, with .NET format codes like N2, P0 (percent) and yyyy-MM-dd for dates. Out-Null or $null = ... discard output you do not want.

Example

function Get-Info {
  [CmdletBinding()] param()
  Write-Verbose 'collecting'                  # only shown with -Verbose
  Write-Host 'progress...' -ForegroundColor Cyan   # display, not output
  [pscustomobject]@{ Name = 'disk'; UsedGB = 41.53 }
}
$r = Get-Info                                 # screen shows: progress...
$r.UsedGB                                     # 41.53  (the object was captured)
Get-Info -Verbose | Out-Null                  # VERBOSE: collecting
Get-ChildItem $PSHOME -File | Select-Object -First 3 Name, Length |
  Format-Table -AutoSize                      # display only, at the very end
'{0} is {1:N1} GB' -f 'disk', 41.53           # disk is 41.5 GB
$text = Get-Process -Id $PID | Out-String     # render as one string
$text.GetType().Name                          # String

Remember

  • Output goes down the pipeline; Write-Host only displays
  • Write-Verbose / Warning / Error keep messages out of captured data
  • Format-* only at the end; Out-String, Export-Csv or ConvertTo-Json for data

Watch out for

  • Get-Process | Format-Table | Export-Csv: the CSV contains formatting objects, not processes.

Check yourself

  1. A function prints a message with Write-Output and returns a number. What does `$x = Func` contain?
  2. Where should Format-Table appear in a pipeline?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/format-table