For my readers who are just discovering my Friday posts, let me remind you that these are not necessarily practical, production worthy PowerShell scripts and functions. They are meant to be fun, yet educational. For example, in today's Friday Fun I have a function that takes string input and writes colored output to the console. So while you may not need the function itself, you might learn something about writing advanced functions, arrays, Write Host and more. So today is all about rainbows, unicorns and puppies.
First off, tt is important to remember that the PowerShell host is not the same as the PowerShell pipeline. The host is the application that is running PowerShell. It might be the PowerShell console you are used to using with the blue background, PowerShell.exe. Or it might be the Integrated Script Editor. Or a hosted application like SAPIEN's PrimalScript. The Write-Host cmdlet writes directly to the host and not the pipeline, ie no objects. This is critical because you can only work with objects. This is why you can't save Write-Host output to a text file: it was written to the host and not the pipeline.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
My function leverages Write-Host to write pretty colored text.
[cc lang="PowerShell"]
Function Out-Rainbow {
<#
.Synopsis
Write rainbow colored output to the console.
.Description
This function takes string input and writes each word in a random color to the host.
The function works best with the PowerShell console.
.Parameter Message
The string of text to colorize.
.Parameter Background
Temporarily change the background color. The screen will be cleared. At the end of the
command the background color will be changed back and you will manually need to run
Clear-Host.
Valid colors are: "Black","DarkMagenta","DarkRed","DarkBlue","DarkGreen","DarkCyan",
"DarkYellow","Red","Blue","Green","Cyan","Magenta","Yellow","DarkGray","Gray","White"
.Example
PS C:\>"Take the first step in faith. You don't have to see the whole staircase,",
"just take the first step.",
" --Martin Luther King, Jr." | out-Rainbow
.Example
PS C:\> (get-process w* | out-string).Split("`r") | out-rainbow
You'll get better results by converting the output to a string and then splitting it so
that each line is processed completely by the function.
.Notes
NAME: Out-Rainbow
AUTHOR: Jeffery Hicks
VERSION: 1.0
LASTEDIT: 01/21/2011
Learn more with a copy of Windows PowerShell 2.0: TFM (SAPIEN Press 2010)
.Link
Http://jdhitsolutions.com/blog
.Link
Write-Host
.Inputs
Strings
.Outputs
None
#>
Param (
[Parameter(Position=0,Mandatory=$False,HelpMessage="Enter a message to display.",
ValueFromPipeline=$True)]
[string[]]$Message,
[Parameter(Mandatory=$False,ValueFromPipeline=$False)]
[ValidateSet("Black","DarkMagenta","DarkRed","DarkBlue",
"DarkGreen","DarkCyan","DarkYellow","Red",
"Blue","Green","Cyan","Magenta","Yellow",
"DarkGray","Gray","White")]
[string]$Background=$Host.UI.RawUI.BackGroundColor
)
Begin
{
#measure the $Message variable. A value of 0 means it was piped in
#and a value greater than 0 means it as passed as a parameter
#This has an affect on the processed output.
if (($message | measure-object).Count -eq 0)
{
Write-Verbose "Pipelined input"
$Pipelined=$True
}
#define the array of valid colors
$AllColors=@(
"Black","DarkMagenta","DarkRed","DarkBlue",
"DarkGreen","DarkCyan","DarkYellow","Red",
"Blue","Green","Cyan","Magenta","Yellow",
"DarkGray","Gray","White"
)
Write-Verbose "Omitting $($host.ui.RawUI.Backgroundcolor) from color array"
#filter out the current background color
$colors=$AllColors | Where {$_ -ne $host.ui.RawUI.Backgroundcolor}
#Check if -Background was called and if the value is different than the current
#background.
if ($Background -ne $Host.UI.RawUI.BackgroundColor)
{
#save current color
$SavedBGColor=$Host.UI.RawUI.BackgroundColor
#set background color
$Host.UI.RawUI.BackgroundColor=$Background
#need to clear the host for this to work properly
Clear-Host
Write-Verbose "Changed background color ro $Background"
}
} #close Begin
Process
{
ForEach ($m in $Message) {
Write-Verbose "Splitting message $m"
#split the line into a word array
$arr=$m.Split()
Write-Verbose "Now have $($arr.count) words"
for ($i=0;$i -lt $arr.count;$i++)
{
#write each word followed by a space. Don't insert a new line
Write-Host "$($arr[$i]) " -foregroundcolor $colors[(Get-Random -Min 0 -max ($colors.count-1))] -NoNewline
} #for
if (-Not $Pipelined)
{
#if not pipelined input then add a carriage retrun
Write-host `r
}
} #foreach
#add a carriage return after each processed object
write-host `r
} #close Process
End
{
#change the background color back if there is a saved color
if ($SavedBGColor)
{
Write-Verbose "Returning background color to $SavedBGColor"
$host.UI.RawUI.BackgroundColor=$SavedBGColor
}
#write a carriage return for visual clarity
Write-Host `r
Write-Verbose "We've reached the end of the rainbow"
} #close End
} #end function
[/cc]
Write-Host has some useful parameters like -Foregroundcolor which let you specify a text color. However, not every host supports it. But for our purposes, assuming you are using the standard PowerShell console we're good. My Out-Rainbow function takes a message string, or a collection of them, then splits each line into it's component words.
[cc lang="PowerShell"]
ForEach ($m in $Message) {
Write-Verbose "Splitting message $m"
#split the line into a word array
$arr=$m.Split()
Write-Verbose "Now have $($arr.count) words"
[/cc]
The function then goes through each word in the array, $arr, and writes it to the host with a color randomly selected from an array.
[cc lang="PowerShell"]
for ($i=0;$i -lt $arr.count;$i++)
{
#write each word followed by a space. Don't insert a new line
Write-Host "$($arr[$i]) " -foregroundcolor $colors[(Get-Random -Min 0 -max ($colors.count-1))] -NoNewline
} #for
[/cc]
The function omits the current background color from the array so you don't have any "invisible" words. You can also use the -Background parameter to temporarily change it. I find Black or White work best. The function will restore your original color, but you'll want to run CLS afterwards.
The function automatically converts objects to strings, so sometimes you can do this:
To fully convert cmdlet output takes a little sleight of hand. You need to convert it all to a string then split it at each line return. I could probably include code in the function to handle this automatically but that will have to wait for a future version.
Download Out-Rainbow.ps1
I love it when I learn something new. Use the -Stream parameter with Out-String so you can do this:
PS C:\> get-process | out-string -stream | out-rainbow