Understanding How Streams Work in PowerShell 7
Much like Unix, PowerShell has the concept of streams. It’s important to understand how the flow of data output works within PowerShell. By leveraging the power of streams and their capabilities, you will be able to create better troubleshooting and more useful output.
In this article, we are going to explore the different streams that are available and how your functions and scripts can take advantage of the streams!
What Exactly Are Streams
The output from a given command can be directed into different streams, think of channels, that can be acted upon later. By default, output that is not explicitly redirected will go to the success stream. So what exactly are the available streams?
- Success (Output)
Though it may not be listed above, there is one more stream operator that you can use. If you specify an
* you can catch all streams and redirect those streams as needed. This may be more convenient than individually and chaining the streams you want to redirect together.
Most of the streams are self-explanatory, but the last one is a bit unique. Introduced in PowerShell 5, the information stream was intended to ensure that nothing went to the host directly. Before this point, cmdlets like
Out-Host sent data directly to the host program. The host program could be something like the PowerShell console, or Visual Studio Code console.
The reason that this is problematic is that if you wanted to later direct that output to somewhere other than the host, you wouldn’t be able to. With the introduction of the information stream, the
Out-Host cmdlets were rewritten to send the output to the information stream instead. By doing this, you can redirect the output if necessary and gain further control over what is output to the console screen!
So now that we know that all of the data in PowerShell is segmented into different streams, how can we redirect data intended for one stream into another? Using the below syntax, it becomes very easy to do so. Below are the three PowerShell redirection operators.
>, sends a specified stream to a file
>>, appends a specified stream to a file
>&1, redirects the specified stream to the success stream
By default, if no stream is specified, the success stream is used. Also of note is the fact that you only redirect other streams to the success stream.
You may not realize but you can chain the redirections. What this allows you to do is take different streams and by redirecting them to the success stream, then send that resulting success stream to a file. An example of chaining is shown below.
# Retrieve both the C:\ directory and then a Fakepath relative to the current directory
# Success output will be directed test.txt
# If an error is encountered, direct that to the success stream, and then to test.txt
PS C:\> Get-ChildItem "C:\","Fakepath" 2>&1 > .\test.txt
As you can see from the output, when we first performed the redirected output, nothing went to the host. After pulling the content from our
test.txt file shows both the success and failure.
Stream Manipulation Examples
What are the practical applications of redirecting output then? Oftentimes, we want to do this for logging our scripts to a file. This is, in fact, one of the most common reasons to use this functionality. Often you want to make sure you are getting a proper log of what is happening in your script and function.
Early on in PowerShell, it was always considered bad practice to utilize
Write-Host except in very specific scenarios. In early versions,
Write-Host didn’t respect any of the streams and negotiated directly with the console itself. This meant dealing with the data was very difficult. Starting in PowerShell 5.1
Write-Host became a wrapper for
Write-Information which writes to the new information stream and respects all the redirection operations.
With that in mind, what if we wanted to suppress all of the
Write-Information content but still log this a file?
# Redirect Write-Host output to the log.txt file
Write-Host "Log Text" 6>> .\log.txt
# Redirect the Write-Information output to the log.txt file
Write-Information "Log Text" -InformationAction 'Continue' 6>> .\log.txt
You may wonder what the
InformationAction value of
Continue is. By default,
Write-Information has a setting of
SilentlyContinue which means the output would not show on the console and only go to the stream. If you omit the redirection and use
Continue, then you will also get the output to the console just like
Redirect All Script Output to a File
Rather than individually writing out each redirection within your script, you can redirect the entire script output itself when you run it by using the special
* redirection operator.
.\script.ps1 *> log.txt
Suppress Output from a Stream
Sometimes you want to make sure that the output of any given cmdlet or function doesn’t display at all. To do this you can redirect to the automatic variable
$null. This is faster than piping the output to
# Only redirects output stream data
PS C:\> Get-ChildItem > $null
# Truly redirect all output to $null
PS C:\> Get-Childitem *> $null
Redirection has been around for a long time in many languages, by utilizing the same functionality in PowerShell, it becomes easy for even veteran Linux command-line administrators to jump in and be successful. Using the same for logging means that we can understand when things go wrong.
Though you may not ultimately use it that often in practice, understanding how streams work and how to redirect those streams is crucial to mastering the PowerShell language.