Understanding streams in PowerShell
In the past, we have spoken about how cmdlets output objects, and how output can be piped from one cmdlet to another. If you ever encountered errors or warnings or verbose output in the execution that involved outputting content to a file, these errors, warnings, verbose outputs… none of them is passed through the pipe into, say, the export cmdlet. Ever wondered why?
I speak about the nature of output in PowerShell, in my book:
Imagine the setup to be like this: there is a room, which has a heap of wet clothes. There is a camera pointing to the clothes, right near the window. The camera is hooked up to a large display, which is placed at the window, instead of plain glass. You can look into the room only through the display. At the moment, you can see the wet clothes on the screen. You cannot touch them, smell them, or weigh them; only see them.
The wet clothes are passed through a pipe into an electric dryer. The dried clothes are sent out of the machine. What you see now is dry clothes, and you know they are dry because someone just picked them up and unfurled them, and the clothes unfurled rather smoothly.
Now, imagine you placed the dryer right next to you, between you and the screen. The sequence now is, wet clothes > camera > screen > dryer > you. Can you take the image and dry it? Or do the wet clothes physically disappear if you turn off the screen? In this analogy, the camera acts as the formatting rules, the display is the information stream, and the screen is the host.
Streams in PowerShell are like parallel tracks, each train picking a track to run on. Imagine there are five tracks, one each for success (a.k.a. the output), error, warning, verbose output and debugging. These tracks don’t connect to each other by themselves, so the error stream does not send content to the success stream. You would need an explicit redirection if you want to achieve that. Pipelines use the success stream for all operations.
Assignments also use the success stream. This is the reason why you can run a cmdlet and directly assign its output into a variable by means of assignment, like:
$Files = Get-ChildItem .
Here are all of the streams (in order) in PowerShell:
There are six streams, that we know now. One of these streams is picked based on what’s being sent by the cmdlet, but where does the output go?
The host. In other words, your PowerShell console. By default. In a moment, we will see that we can redirect outputs to other places as well.
Note: Up until PowerShell 5, there was no Information stream. All of the content, if not picked up by any other cmdlet or stream, the output got sent to the host, without the use of any stream.
If you’d like to explicitly redirect the output to the host, use the
'Just a message I want to send to the screen.' | Out-Host
However, one thing to remember is that
Out-Host did not use any stream for its output. The streams could only send content to
Out-Host could not (or did not) send anything to any of the streams. It simply sent content to the host program (in case of the PowerShell console, it’s the console screen). Even plain text cannot be sent to text files after
Out-Host, because redirection of output to files uses the success stream.
Every PowerShell scripter (including the inventor of PowerShell) would advise you against using these cmdlets for anything at all. It’s supposed to be used only in very specific situations.
By now we know that “host” here is the program occupying the screen.
Read-Host is similar to
Write-Host; it directly interacts with the host program, and collects text. The output of
Read-Host, though, is sent into the success stream. Therefore, you can use this cmdlet to even assign content to variables.
# Try it yourself $Name = Read-Host -Prompt 'Enter your name' # Call the variable to reveal the value $Name
Let’s try an exercise. List out all the commands that can write content—write an error, write an output, whatever.
Hint: Remember verbs and nouns.
The Information stream
With PowerShell 5, the PowerShell Team introduced the Information Stream (and with it,
$InformationPreference, etc.). They also ensured that nothing went to the host directly—now, the cmdlets like
Out-Host used the information stream to send their output. Of course, again, the default culmination point was still the host.
How did this help?
Now, output of
Write-Host can be sent to files by redirecting this stream to the success stream, if needed!
Redirecting output across streams
Redirection of output is straight-forward in PowerShell. We use the stream number and the redirection operator. For instance, if you would like to redirect a certain message to a certain file:
Write-Host 'The message I would like to redirect to a file.' 6> Message.txt
If you would like to redirect the output to the success stream instead (merging the stream with the success stream):
Write-Host 'The message I would like to redirect to Success.' 6>&1
Any stream can be merged with any other stream. Replace the source stream number and the destination stream number with the stream numbers of your choice. If you would like to directly send the output of a certain stream to a file, do it this way:
Write-Warning 'Here is a warning that you should care about.' 3> Warning.txt
If you would like to append the content in a file, use the redirect-and-append operator,
Streams are a powerful aspect of PowerShell. They organise the different kinds of output and channelise them in a way that benefits administrators to a great extent. Different streams contain different kinds of data in them. Content from one stream can be merged with another, or a redirection operator can be used to directly output content into a file.
By default, if no redirection happens, the default redirection during the formatting is to the Information stream, which is connected to the host program. This way, all of the output, errors, warnings, verbose logging, and everything appears on the console, leading us to believe that everything is text, and everything flows to the console.
Understanding how the streams work and learning to work wit the streams would enable us to write better scripts and create better automation solutions.