Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to write verbose output.
Hey, Scripting Guy! The other day, you said that I should not use Write-Host. I even read that such usage is dangerous to the health of small canines in 2012 Scripting Games Commentary: STOP USING WRITE-HOST!.
—BP
Hello BP,
Microsoft Scripting Guy, Ed Wilson, is here. This morning I am sipping a cup of English Breakfast tea with a cinnamon stick and a squeeze of lemon. I am using my Surface Pro 2 to check my scripter@microsoft.com email, and I saw another email from you. I decide to crank up Alan Parsons on my 64-gig Zune HD, and dive right in.
Use Write-Verbose
To provide status updates, detailed tracking information, and the like, use the Write-Verbose cmdlet The cool thing about using Write-Verbose is that I never need to modify the script. For example, if I use a whole bunch of Write-Host statements, eventually I may become tired of the clutter. But with Write-Verbose, I can turn on the extra output only if I decide I need it. In addition, because Write-Verbose writes to the verbose output stream, I can decide if I want to capture that output. This makes it a great option.
Easy way to Write-Verbose
By default, Windows PowerShell is set up to use Write-Verbose. The issue is that out of the box, verbose messages do not display. The $VerbosePreference preference variable controls if Write-Verbose statements appear. By default, the value of $VerbosePreference is set to SilentlyContinue, which means the messages do not appear. Because this is a simple preference variable, all I need to do is to change it in my profile. Now all verbose messages will appear in the output. This is probably not a good idea. If I want to change it, the statement is this:
$VerbosePreference = "continue"
If I do not want to make the change in my profile (we really, really do not want to make this change in our profiles), I can easily change it in my script. To do this, I first read the old value of $verbosePreference, store that in a variable, and then change $verbosePreference to continue. Here is the command to do this:
$oldverbose = $VerbosePreference
$VerbosePreference = "continue"
Now, when I am done doing whatever I need to do, I simply set the old value. Here is that command:
$VerbosePreference = $oldverbose
To put this into a function, I create a switched parameter named $verbose, and if I call that parameter, I change the existing value of $verbosePreference to continue, and then I can use Write-Verbose to display progress, updates, and other information. Here is the complete function:
Function test-verbose
{
Param ([switch]$verbose)
if($verbose) {
$oldverbose = $VerbosePreference
$VerbosePreference = "continue" }
Write-Verbose "verbose output"
"Regular output"
$VerbosePreference = $oldverbose
}
This is pretty simple. When I call the function the first time, only regular output displays. When I call the function with –verbose, the verbose output appears along with the regular output. This is shown in the following image:
Easier way to verbose output
The point of the earlier command is to show you how the preference variables effect the way Write-Verbose works. (It is the same thing for other cmdlets, such as Write-Debug). But there is a slightly easier way to do this, and it is to use the [cmdletbinding()] attribute.
Note There is a bit of confusion because that I must include Param() in my function—even if I am not accepting parameterized input to the function. The reason is that I am using [cmdletbinding()] as an attribute for my parameters. It does more than turn on automatic support for Write-Verbose. See the following topic (which, incidentally, does not say anything about Write-Verbose) for details: about_Functions_CmdletBindingAttribute.
All I need to do is add the [cmdletbinding()] attribute over the Param()statement, and I automatically gain support for Write-Verbose. Here is the command:
Function Test-VerboseTwo
{
[cmdletbinding()]
Param()
Write-Verbose "Verbose output"
"Regular output"
}
This is seven lines as opposed to ten lines of script. It saves me three lines. Of course, [cmdletbinding()] does more than automatically wire Write-Verbose, so the savings are potentially greater. To be honest, the script is not quite as easy to read, and [cmdletbinding()] (which does not appear via Tab expansion in the ISE, nor does it really tell me what it is doing) behaves more like a black box. But hey, there is a whole topic that tells me what this little attribute does, so it is not really a black box.
Here is the new function in action:
It is all good, and pretty simple. Perhaps best of all, no small canines were harmed.
BP, that is all there is to writing verbose output. Script Week will continue tomorrow when I will talk about more cool stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy