Scripting Best Practices, or Write-Host Considered Harmful

Disclaimer: this is going to sound like I actually know what I’m doing.  Let’s be honest – I work in Microsoft, home to the people who created PSH, .NET, and the native internals that people invoke with Add-Type and other arcane arts.  There’s no way I can say I know what I’m doing relative to those people, emails of whom I often read and am in awe.

That said, I am starting to have to maintain some scripts that I didn’t write.  From long and painful experience, I know that each person writes a script differently, from commenting style to indenting style on the surface, and the logical code flow (such as “do I write an all-encompassing library and have each script dependent on it, or do I include the functions in the script so the file is stand-alone?”) and output.

Dearly beloved, output is what brings us here to day.  Specifically, Write-Host.  It is a boon to those who longed for the ability to colour text, or who mastered the incantations of colouring BAT file output.  It’s fantastic for stuff that is we don’t want hidden under the hood, which would be Write-Verbose.  It is even better for avoiding stuff that is of use only to other script-authors, either ones cribbing functionality, or ones forced to maintain the script, which would be Write-Debug.

I’ll treat Write-Progress, Write-Warning, and Write-Error as self-evident.

However, as pretty and useful as Write-Host can be, it has a fatal failing:

It does not output to STDOUT.

Let me say that again: it does not output to STDOUT.  Put another way, it breaks just about every useful code path that PSH so painstakingly provides for any output from the script or function.

It has absolutely no place in returning the desired data in the script.   It is worse than shoving output through Format-List or Format-Table.  Those mistakes, and they are mistakes, at least convert usable object data into Microsoft.PowerShell.Commands.Internal.Format.StartData, which is nearly useless in terms of consuming on the pipeline.  Cramming data through Out-Host means it’s lost, unless the consumer wrap it in further hackosity as detailed in Capturing Write-Noun Cmdlet Output.

But you really shouldn’t.  At the very least, show some mercy for the consumer of your script or function’s output and implement the –PassThru switch.

I say this again: but you really shouldn’t use Write-Host in the first place.