Reputation: 60351
There are a number of different ways to output messages. What is the effective difference between outputting something via Write-Host
, Write-Output
, or [console]::WriteLine
?
I also notice that if I use:
write-host "count=" + $count
The +
gets included in the output. Why's that? Shouldn't the expression be evaluated to produce a single concatenated string before it gets written out?
Upvotes: 222
Views: 308489
Reputation: 52577
Write-Output
should be used when you want to send data on in the pipe line, but not necessarily want to display it on screen. The pipeline will eventually write it to out-default
if nothing else uses it first.
Write-Host
should be used when you want to do the opposite.
[console]::WriteLine
is essentially what Write-Host
is doing behind the scenes.
Run this demonstration code and examine the result.
function Test-Output {
Write-Output "Hello World"
}
function Test-Output2 {
Write-Host "Hello World" -foreground Green
}
function Receive-Output {
process { Write-Host $_ -foreground Yellow }
}
#Output piped to another function, not displayed in first.
Test-Output | Receive-Output
#Output not piped to 2nd function, only displayed in first.
Test-Output2 | Receive-Output
#Pipeline sends to Out-Default at the end.
Test-Output
You'll need to enclose the concatenation operation in parentheses, so that PowerShell processes the concatenation before tokenizing the parameter list for Write-Host
, or use string interpolation
write-host ("count=" + $count)
# or
write-host "count=$count"
BTW - Watch this video of Jeffrey Snover explaining how the pipeline works. Back when I started learning PowerShell I found this to be the most useful explanation of how the pipeline works.
Upvotes: 306
Reputation: 310822
For usages of Write-Host
, PSScriptAnalyzer
produces the following diagnostic:
Avoid using
Write-Host
because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, useWrite-Output
,Write-Verbose
, orWrite-Information
.
See the documentation behind that rule for more information. Excerpts for posterity:
The use of
Write-Host
is greatly discouraged unless in the use of commands with theShow
verb. TheShow
verb explicitly means "show on the screen, with no other possibilities".Commands with the
Show
verb do not have this check applied.
Jeffrey Snover has a blog post Write-Host Considered Harmful in which he claims Write-Host is almost always the wrong thing to do because it interferes with automation and provides more explanation behind the diagnostic, however the above is a good summary.
Upvotes: 9
Reputation: 2355
Regarding [Console]::WriteLine() - you should use it if you are going to use pipelines in CMD (not in powershell). Say you want your ps1 to stream a lot of data to stdout, and some other utility to consume/transform it. If you use Write-Host in the script it will be much slower.
Upvotes: 0
Reputation: 1354
Here's another way to accomplish the equivalent of Write-Output. Just put your string in quotes:
"count=$count"
You can make sure this works the same as Write-Output by running this experiment:
"blah blah" > out.txt
Write-Output "blah blah" > out.txt
Write-Host "blah blah" > out.txt
The first two will output "blah blah" to out.txt, but the third one won't.
"help Write-Output" gives a hint of this behavior:
This cmdlet is typically used in scripts to display strings and other objects on the console. However, because the default behavior is to display the objects at the end of a pipeline, it is generally not necessary to use the cmdlet.
In this case, the string itself "count=$count" is the object at the end of a pipeline, and is displayed.
Upvotes: 17
Reputation: 85
From my testing Write-Output and [Console]::WriteLine() perform much better than Write-Host.
Depending on how much text you need to write out this may be important.
Below if the result of 5 tests each for Write-Host, Write-Output and [Console]::WriteLine().
In my limited experience, I've found when working with any sort of real world data I need to abandon the cmdlets and go straight for the lower level commands to get any decent performance out of my scripts.
measure-command {$count = 0; while ($count -lt 1000) { Write-Host "hello"; $count++ }}
1312ms
1651ms
1909ms
1685ms
1788ms
measure-command { $count = 0; while ($count -lt 1000) { Write-Output "hello"; $count++ }}
97ms
105ms
94ms
105ms
98ms
measure-command { $count = 0; while ($count -lt 1000) { [console]::WriteLine("hello"); $count++ }}
158ms
105ms
124ms
99ms
95ms
Upvotes: 3
Reputation: 17850
Apart from what Andy mentioned, there is another difference which could be important - write-host directly writes to the host and return nothing, meaning that you can't redirect the output, e.g., to a file.
---- script a.ps1 ----
write-host "hello"
Now run in PowerShell:
PS> .\a.ps1 > someFile.txt
hello
PS> type someFile.txt
PS>
As seen, you can't redirect them into a file. This maybe surprising for someone who are not careful.
But if switched to use write-output instead, you'll get redirection working as expected.
Upvotes: 32