Caveat:
Write-Host
is meant for to-display output, not for outputting data - it bypasses PowerShell's success output stream (PowerShell's stdout equivalent), so that output from Write-Host
cannot (directly[1]) be captured in a variable, nor redirected to file - see the bottom half of this answer for more information.
Use Write-Output
or - preferably - PowerShell's implicit output behavior to output data, suitable for further programmatic processing.
In addition to this fundamental difference, Write-Host
and Write-Output
also differ in how they handle arguments:
# What Write-Host prints to the display is a *single string* that is
# the space-separated list of the (stringification of) its arguments.
PS> Write-Host file1, '>>', file2
file1 >> file2 # printed to *display* only
# Write-Output outputs each argument - whatever its data type - *separately*
# to the success output stream.
# In the case of *string* arguments, each string renders *on its own line*.
PS> Write-Output file1, '>>', file2
file1
>>
file2
Using implicit output, the equivalent of the above Write-Output
command is:
# Send an array of 3 strings to the success stream.
PS> 'file1', '>>', 'file2'
file1
>>
file2
If you redirect the Write-Output
command or its implicit equivalent to a file (with >
/ Out-File
or Set-Content
[2]), you'll get the same 3-line representation.
Additionally, Write-Host
performs simple .ToString()
stringification on complex objects, which often results in unhelpful output; by contrast, Write-Output
/ implicit output uses PowerShell's rich formatting system:
# Write-Host: Unhelpful representation; entries are enumerated
# and .ToString() is called on each.
PS> Write-Host @{ foo = 1; bar = 2 }
System.Collections.DictionaryEntry System.Collections.DictionaryEntry
# Write-Output / implicit output: rich formatting
PS> @{ foo = 1 }
Name Value
---- -----
foo 1
bar 2
Note: If you use the Out-Host
cmdlet and pipe a command to it (e.g.
@{ foo = 1; bar = 2 } | Out-Host
) you do get the usual, rich output formatting that you get via Write-Output
/ by default - while still printing to the display only.
If you do want to output a single line as data, use a quoted string; to reference variables and embed subexpressions in a string, use an expandable string (string interpolation), "...
" (see about_Quoting_Rules), or use string concatenation (+
)
$arg1 = 'file1'; $arg2 = 'file2'
# Expandable string
PS> "$arg1 >> $arg2"
file1 >> file2
# String concatenation
PS> $arg1 + ' >> ' + $arg2
file1 >> file2
[1] In PowerShell v5 or higher, you can capture/redirect Write-Host
output, via the information output stream, number 6
; e.g.: $writeHostOutput = & { Write-Host hi } 6>&1
. However, note that the information output stream is primarily designed to work with the PSv5+ Write-Information
cmdlet and the common -InformationAction
parameter.
[2] With strings only, >
/ Out-File
behave the same as Set-Content
, except that in Windows PowerShell a different default character applies (not in PowerShell Core). For more information about the differences, see this answer.