添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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?

Write-Output when you're emitting results. Write-Host when you're emitting logging information. Never use [console]::writeline(). – JohnL Aug 31 '13 at 2:01 @Backwards_Dave Because you have Write-Host.... Ok, I may have been under some impression that it showed a new console window (it was quite a long time ago). That doesn't happen, but the fact remains that it's not the powershell idiom and there's nothing you can do with [console]::writeline("hello world") that you can't do with Write-Host "hello world". Another, better, more recently applicable answer is that write-host wraps write-information so its data gets put on a stream like write-error so you can capture it and use it elsewhere. [console]::writeline() does not do that – JohnL Oct 18 '16 at 11:35

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)
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.

In an Azure WebJob [console]::WriteLine works but Write-Host will result in an error: The Win32 internal error "The handle is invalid" 0x6 occurred while setting character attributes for the console output buffer. Don't ask me why. – Gil Roitto Nov 3 '17 at 12:19 Correct me if I'm wrong, but I believe Write-Output is the default e.g. if you have a PsObject and you just spit it out to the screen by doing this $object it will actually do the same thing as this Write-Output $object. Might be worth mentioning – Kolob Canyon Aug 22 '18 at 21:10 There is new guidance: avoid using Write-Output when possible. See github.com/PoshCode/PowerShellPracticeAndStyle/issues/… > Use return only for ending execution. > Avoid Write-Output (...). Instead, when you want to make output clearer, just assign output to a relevantly named variable. and put that a variable on a line by itself to signal explicit output. > Write-Output -NoEnumerate is broken on PowerShell 6 and has been for 16 months or longer -- there's no plan to fix it. In summary: > DO NOT USE Write-Output -- EVER. – Jeroen Wiert Pluimers Mar 5 '19 at 10:48

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

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.

It's possible to capture Write-Host Output if you use Start-Process Powershell .\a.ps1 -RedirectStandardOutput somefile.txt There's trouble with encoding, though (file will be in SystemDefaultEncoding). – MKesper Nov 30 '16 at 10:39

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.

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++ }}
105ms
105ms
measure-command { $count = 0; while ($count -lt 1000) { [console]::WriteLine("hello"); $count++ }}
158ms
105ms
124ms
                Write-Output and Write-Host serve different purposes, so there is no point in comparing their performance. Yes, direct use of .NET types and their methods is faster, but you miss out on the higher-level features that PowerShell cmdlets can provide. [Console]::WriteLine() is akin to Write-Host in the case at hand, but won't work in all circumstances, because not all PowerShell hosts are consoles.
                    – mklement0
                May 13 '18 at 1:14
  

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, use Write-Output, Write-Verbose, or Write-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 the Show verb. The Show 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.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.

How to make this PowerShell function return a plain string, but not return an array of string? see more linked questions… site design / logo © 2020 Stack Exchange Inc; user contributions licensed under cc by-sa 4.0 with attribution required. rev 2020.2.7.36004