2

An example when using Write-Host makes sense

In the PowerShell community, there is some debate about the usage of the Write-Host cmdlet.  The debate stems from the fact that the output of the Write-Host cmdlet places strings of text on the monitor and not in the pipeline.  Since PowerShell cmdlets are supposed to create objects  some may think you are developing poor code should you be caught using Write-Host.  I personally beg to differ.  Although nicely formatted columns can present data in a very orderly package, too much displayed information can hide what is requiring the user’s attention. This is where the Write-Host cmdlet can excel.  For the novice user, the color formatting capabilities of the Write-Host cmdlet can be used to highlight what needs their attention and focuses them on the task at hand.

Recently I presented a project to the Cincinnati PowerShell User Group to provide help desk technicians with many of the answers to the questions that they would not want to ask the end user.  Let’s face it–either the user does not know the answer, does not want to tell you the truth, or it might be too time-consuming to manually extrapolate the data from an RDP session.  The problem here is that many help desk technicians are not PowerShell savvy.  You need to be aware of the consumers of your code and present information in a way that meets their needs.

In the case of the help desk, we can provide cmdlets to help extract information quickly from a remote client.  We can then have PowerShell flag values that would be considered out of an acceptable range.  This approach would allow the PowerShell-challenged staff to focus on what is requiring their attention without filtering cmdlet output.  The code below is an example of how to extract a client’s hard disk free space.  This simple example will demonstrate using color to flag potential problems.

Function Get-DiskInfo
{
    Param(
        $ComputerName = $env:COMPUTERNAME,
        [Switch]$PassThru
    )

    Function Get-ColorSplat
    {
        # Create color Splats
        $C1 = @{ForegroundColor="Green";BackgroundColor="DarkGreen"}
        $C2 = @{ForegroundColor="Yellow";BackgroundColor="DarkYellow"}
        $C3 = @{ForegroundColor="White";BackgroundColor="DarkRed"}
        $C4 = @{ForegroundColor="Blue";BackgroundColor="Gray"}

        # Create color constants in the previous scope.
        New-Variable -Name "Good" -Value $C1 -Scope 1
        New-Variable -Name "Problem" -Value $C2 -Scope 1
        New-Variable -Name "Bad" -Value $C3 -Scope 1
        New-Variable -Name "Header" -Value $C4 -Scope 1
    } # End: Get-ColorSplat

    Function Write-ColorOutput
    {

        Param($DiskInfo)

        # Display the headers.
        Write-host "DiskInfo | FreeSpaceGB | PercentFreeSpace"

        # Display the data.
        ForEach ($D in $DiskInfo)
        {
            $DeviceID = $D.DeviceID.PadRight(6)
            $FSGB = $D.FreeSpaceGB.ToString().PadRight(6).Remove(5)
            $PFS = $D.PercentFS.ToString().PadRight(6).Remove(5)

            If ($D.PercentFS -ge 80)
            { Write-Host "$($DeviceID)   | $($FSGB)       | $($PFS)" @Good }
            ElseIf (($D.PercentFS -lt 80) -and ($D.PercentFS -GE 60))
            { Write-Host "$($DeviceID)   | $($FSGB)       | $($PFS)" @Problem }
            Else
            { Write-Host "$($DeviceID)   | $($FSGB)       | $($PFS)" @Bad }

        }
    }

    # Get the color splats
    Get-ColorSplat

    $DiskInfo = Get-WmiObject Win32_LogicalDisk -ComputerName $ComputerName |
     Select-Object -Property DeviceID,
     @{Name="FreeSpaceGB";Expression={$_.Freespace/1GB}},
     @{Name="PercentFS";Expression={($_.FreeSpace/$_.Size)*100}}

     If (!$PassThru) {Write-ColorOutput -DiskInfo $DiskInfo}
     Else {Write-Output $DiskInfo}
}

This cmdlet has a switch parameter that I want to bring to your attention, –PassThru.  Since this code is intended for users who are not avid PowerShell users, the default behaviour is to display the color-coded information.  The usage of the -PassThru parameter suppresses the use of Write-Host and allow an object to be passed to the pipeline.  In this case, we have object in, object out.  By doing this we have the capability of continuing to pass our object into the pipeline.  Here are some examples:

Write-Host

In this example we see the default output of color-coded information drawing the technician to the drives that need attention.

PS> Get-DiskInfo -ComputerName JasonPC2 -PassThru | Format-Table -AutoSize

DeviceID      FreeSpaceGB        PercentFS
--------      -----------        ---------
C:       34.6056213378906 31.7261065852248
D:       202.438598632813 84.9355612944946
E:       79.9115943908691 33.5278754613268
Z:       83.1089553833008 8.95466512825099

In this example, the –PassThru parameter is utilized and we are once again working with objects. The best of both worlds is possible.  Remember to always consider the audience of your code and display information to them that is relevant and fits their skill level.

Filed in: Articles Tags: ,

2 Responses to "An example when using Write-Host makes sense"

  1. Kirk Munro says:

    While I agree that there are some debatable valid uses for Write-Host (only one comes to mind for me), I don’t agree at all that this is one of them.

    In this example, the default use of the Get-DiskInfo function outputs object data to the console. The end user doesn’t know (and shouldn’t care) how that data is output, it is simply output. Any command that outputs data can have that data pass through the pipeline, so users with any familiarity at all with PowerShell would tend to pipe this output to some cmdlet, see that it’s not working, and then start scratching their head because something is broken. In this case it’s the design of the command that is broken, because it is outputting data incorrectly and it is also using the PassThru parameter incorrectly. Why? Because both techniques are not consistent with the rest of PowerShell, so you’re breaking mental models that are already established about command output and about PassThru behaviour and creating more harm than good as a result.

    The correct approach to accomplish what you are trying to do here would be to simply output object data from your command and then apply a coloring model that works for both this command and any other command in PowerShell that outputs data by implementing some proxy functions on top of the Format-* cmdlets, coupled with some commands that allow you to define the default colors to apply in various scenarios when formatting objects. This will give you colored formatting without adding some non-standard inconsistent use of PassThru while confusing users with how they can manage your object output.

    Kirk out.

  2. Jon says:

    I use Write-Host all the time. I’m not a programmer. I use PowerShell to get a job done quickly in my System Admin role. I don’t have the luxury or time to be a purist about “object oriented coding” practices.

Leave a Reply

Submit Comment

© 2016 PowerShell Magazine. All rights reserved. XHTML / CSS Valid.
Proudly designed by Theme Junkie.
%d bloggers like this: