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?

  1. Success (Output)
  2. Error
  3. Warning
  4. Verbose
  5. Debug
  6. Information

The * Stream

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.

Information Stream

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 Write-Host and 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 Write-Host and 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!

Redirecting Output

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.

Untitled 2019 12 26T101619.257
The output from chained redirection example
Untitled

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.

Redirecting Write-Host and Write-Information Output

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-Host or 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 Write-Host.

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 Out-Null.

# Only redirects output stream data
PS C:\> Get-ChildItem > $null
# Truly redirect all output to $null
PS C:\> Get-Childitem *> $null

Conclusion

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.