Weekend Scripter: Welcome to the PowerShell Information Stream
Summary: Learn about the Windows PowerShell information stream in this guest post by June Blender.
Microsoft Scripting Guy, Ed Wilson, is here. Today we have another guest blog post by Honorary Scripting Guy and Sapien technical evangelist, June Blender. Take it away June…
Note This post is updated on August 3, 2015 for the Windows PowerShell 5.0.10240 preview. A previous version described the information stream features in Windows PowerShell 5.0.10018. This post introduces the new information stream in Windows PowerShell 5.0, and it explains the issue it tries to solve and its elegant solution.
In March 2014, I wrote a Hey, Scripting Guy! Blog post, Understanding Streams, Redirection, and Write-Host in PowerShell, which explained the output streams in Windows PowerShell.
The outlier in the stream world has always been the much-maligned Write-Host cmdlet. Windows PowerShell inventor, Jeffrey Snover decried it as Write-Host Considered Harmful. Famously, in his 2012 Scripting Games commentary, Stop Using Write-Host!, Windows PowerShell MVP and first follower, Don Jones, proclaimed that Write-Host kills puppies. That’s a lot of high-powered condemnation for a cmdlet.
It’s all about to change. With the advent of the information stream in Windows PowerShell 5.0, Write-Host is being redeemed. Actually, it's being, well…mainstreamed. And, Windows PowerShell 5.0 includes a new cmdlet, Write-Information, that has the benefits of Write-Host without the costs.
Write-Host and streams
The root of the problem is that in Windows PowerShell versions 1.0 through 4.0, Write-Host output doesn’t go to a stream. It goes straight to the host program, such as the console, ISE, or PowerShell Studio. What happens then is determined by the host program, and it might vary.
Because Write-Host doesn't go to a stream, if you put Write-Host in a script, the end-user can't suppress it, can't save it, and can't redirect it.
- You can't suppress Write-Host output because there's no preference that silences it.
- You can’t save Write-Host output in a variable, because the assignment operator uses the output stream. The Write-Host output is written to the host program, but the variable is empty.
- You can't pass Write-Host output down the pipeline, because only the output stream goes down the pipeline.
- You can't redirect Write-Host output, because redirection sends output from one stream to another, and Write-Host isn't part of any stream.
Write-Host and stream pollution
Despite this very high-level condemnation, people kept using Write-Host, precisely because it doesn't go to the output stream. Write-Host is eco-friendly, because it doesn't pollute the output stream.
The underlying principle is that every command should generate one type of output. For example, Get-Process returns Process objects, and Start-Job returns PSRemotingJob objects.
You never want a command like the following, which returns process objects and a string:
In its own sad way, Write-Host solves this problem. In this version, I replaced Write-Output with Write-Host. Now this function writes a process object and a string, but only the process object is written to the output stream. Typically, the user sees the string, but it's not saved in the variable or passed down the pipeline.
Write-Information and the information stream
The dilemma was how to fix the harmful aspects of Write-Host (can't suppress, capture, or redirect), but keep it from polluting the output stream. And of course, the solution must be backward compatible.
This most elegant solution is provided by the information stream and the Write-Information cmdlet. The information stream is a new output stream that works much like the error and warning streams.
With these new features, you can write messages to the user without polluting the information stream. And you can suppress the messages, capture them, save them, and redirect them.
The information stream has a preference variable, $InformationPreference, with a default value of SilentlyContinue, and a common parameter, InformationAction, to override the preference for the current command. It also has an InformationVariable common parameter that saves the stream content in the specified variable.
The new cmdlet, Write-Information, provides information to the user without polluting the output stream. I think of it as a do-over of Write-Host. Both Write-Host and Write-Information write to the information stream, but they behave differently, because Write-Host must be backward compatible.
Write-Information writes InformationRecord objects (System.Management.Automation.InformationRecord) to the information stream. Its output is determined by the $InformationPreference variable, which is set to SilentlyContinue by default. So, by default, its output is suppressed.
To display a Write-Information message, change the default value of the $InformationPreference variable, or use a value of Continue for the new InformationAction common parameter.
Write-Host also writes InformationRecord objects to the information stream, but it is not affected by the $InformationPreference variable or the InformationAction common parameter. (Windows PowerShell 5.0 is still in preview, so this might change.)
However, you can save the content of Write-Host and Write-Information output in a variable by using the new InformationVariable common parameter.
Because they write to the information stream (stream #6), you can redirect the output of Write-Host and Write-Information to a file. (Notice that redirecting host output suppresses it. Windows PowerShell 5.0 is still in preview, so this might change.)
You can also redirect output from the information stream (stream #6) to standard output (stream #1). (For help, see about_Redirection.) Redirecting to standard output lets you use the assignment operator.
Unless you intentionally redirect them, Write-Information and Write-Host messages still don't pollute the output stream.
Now if someone was to write a function, such as Get-PowerShellProcess (and you still should never do this), the information is suppressed by default and the end-user could display the information without polluting the output stream. (I had to enable cmdlet binding to get the common parameters.)
Write-Host vs. Write-Information
As you adopt Write-Information, keep in mind that there are a few differences:
- Write-Information responds to the values of the $InformationPreference variable and the InformationAction common parameter. Write-Host does not.
- Write-Host has parameters that change its display, for example, ForegroundColor and BackgroundColor. Write-Information does not.
- Write-Information has a Tags parameter like New-ModuleManifest and cmdlets in the AzureResourceManager module. Write-Host does not.
- Write-Host takes value from the pipeline. Write-Information does not.
As you learn Windows PowerShell 5.0, play around with the information stream. And the next time you're tempted to use Write-Host, use Write-Information instead.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy