Last Update: Sep 04, 2024 | Published: Jan 28, 2016
In a previous article I introduced you to the new information stream in PowerShell 5.0. I think this is something that you can incorporate into your own scripts and functions. As I mentioned last time, one of the drawbacks to using PowerShell’s Write-Information cmdlet is that if you want to see messages, then it’s difficult to distinguish between output and messages. Fortunately, Microsoft’s PowerShell team planned ahead and tweaked Write-Host in PowerShell 5.0.
In the past the PowerShell community has frowned upon the use of Write-Host, especially as the means to display results. But it has always been fine for informational messages, especially if you take advantage of the ForegroundColor or BackgroundColor parameters. If you take advantage of those parameters, then you can easily tell the difference between actual output and messages. In PowerShell 5.0, Write-Host is a wrapper for Write-Information. This means you can use Write-Host and get all the benefits of the new information stream.
To demonstrate, here’s a variation on the test function that I used previously.
Function Test-Me2 { [cmdletbinding()] Param() Write-Verbose "InformationPreference = $InformationPreference" Write-Host "Starting $($MyInvocation.MyCommand) " -ForegroundColor Green Write-Host "PSVersion = $($PSVersionTable.PSVersion)" -ForegroundColor Green Write-Host "OS = $((Get-CimInstance Win32_operatingsystem).Caption)" -ForegroundColor Green Write-Verbose "Getting top 5 processes" Get-process | sort WS -Descending | select -first 5 -outvariable s Write-Host ($s[0] | out-string) -ForegroundColor Green Write-Host "Ending $($MyInvocation.MyCommand) " -ForegroundColor Green }
Let’s run the test function.
You’ll notice that I specified an information variable. The information preference doesn’t have an effect on Write-Host. But I have information.
Everything worked as planned, but I probably need to make additional decisions as to what information to display. By the way, you can also use Write-Information in the same command as Write-Host. Messages for the former will only be displayed if you use an InformationPreference of continue while messages for the latter will always be displayed.
Or so I thought until I came up with the approach.
Function Test-Me3 { [cmdletbinding()] Param() write-Verbose "InformationPreference = $InformationPreference" #create a variable that will be easier to work with if ($InformationPreference -eq "Continue") { $Info = $True } if ($Info) { Write-Host "Starting $($MyInvocation.MyCommand) " -ForegroundColor Green Write-Host "PSVersion = $($PSVersionTable.PSVersion)" -ForegroundColor Green Write-Host "OS = $((Get-CimInstance Win32_operatingsystem).Caption)" -ForegroundColor Green } Write-Verbose "Getting top 5 processes" Get-process | sort WS -Descending | select -first 5 -outvariable s If ($Info) { Write-Host ($s[0] | out-string) -ForegroundColor Green Write-Host "Ending $($MyInvocation.MyCommand) " -ForegroundColor Green } }
Sometimes I might want to occasionally see messages from Write-Host, so I’ll check the value of $InformationPreference. If it’s set to continue, then I know to display the messages with Write-Host. To simplify my code, I’ll create a Boolean variable, $Info, at the beginning. Throughout the function, if this value is True, then the Write-Host lines will execute.
As expected, no information is generated.
Writing information in color (Image Credit: Jeff Hicks)
Now my Write-Host messages are displayed in color, and I have data in the information variable.
The PSHost tag is automatically added, and you can see that the source is Write-Host. You can manually add additional tags if you desire.
But I’m probably not going to do that and neither are you. Instead, here’s a proof of concept that lets you add additional tags to each piece of information.
Function Test-Me4 { [cmdletbinding()] Param() Write-Verbose "InformationPreference = $InformationPreference" write-verbose "Information variable = $($PSBoundParameters["InformationVariable"] | out-string)" #create a variable that will be easier to work with if ($InformationPreference -eq "Continue") { $Info = $True } if ($Info) { Write-Host "Starting $($MyInvocation.MyCommand) " -ForegroundColor Green (get-variable $PSBoundParameters["InformationVariable"]).value[-1].Tags.Add("Process") Write-Host "PSVersion = $($PSVersionTable.PSVersion)" -ForegroundColor Green #insert a new tag to the last information entry (get-variable $PSBoundParameters["InformationVariable"]).value[-1].Tags.Add("Meta") Write-Host "OS = $((Get-CimInstance Win32_operatingsystem).Caption)" -ForegroundColor Green (get-variable $PSBoundParameters["InformationVariable"]).value[-1].Tags.Add("Meta") } Write-Verbose "Getting top 5 processes" Get-process | sort WS -Descending | select -first 5 -outvariable s If ($Info) { Write-Host ($s[0] | out-string) -ForegroundColor Green (get-variable $PSBoundParameters["InformationVariable"]).value[-1].Tags.Add("Data") Write-Host "Ending $($MyInvocation.MyCommand) " -ForegroundColor Green (get-variable $PSBoundParameters["InformationVariable"]).value[-1].Tags.Add("Process") } }
I can look at the bound parameters and discover the name of the information variable being used. Then, every time I want to insert a new tag, I can update the variable value. In this last iteration of the function, I’m adding the same tags I used in the very first version of the function. Now I have the best of everything. I can display information messages in color and get property tagged data.
As you can see, the information object has my additional tags.
I would probably create a small helper function to streamline the process of adding additional tags. Please note that this is only necessary when using Write-Host. If you use Write-Information, you can specify all the tags you need.
I’ve probably given you a lot to think about to take some time to experiment and test. When you get ready to take advantage of this feature, I hope you’ll let me know how you are using this new stream and your experiences.