How to properly use the -verbose and -debug parameters in a custom cmdlet
$PSBoundParameters
isn't what you're looking for. The use of the [CmdletBinding()]
attribute allows the usage of $PSCmdlet
within your script, in addition to providing a Verbose flag. It is in fact this same Verbose that you're supposed to use.
Through [CmdletBinding()]
, you can access the bound parameters through $PSCmdlet.MyInvocation.BoundParameters
. Here's a function that uses CmdletBinding and simply enters a nested prompt immediately in order examine the variables available inside the function scope.
PS D:\> function hi { [CmdletBinding()]param([string] $Salutation) $host.EnterNestedPrompt() }; hi -Salutation Yo -VerbosePS D:\>>> $PSBoundParameters____________________________________________________________________________________________________PS D:\>>> $PSCmdlet.MyInvocation.BoundParametersKey Value --- ----- Salutation Yo Verbose True
So in your example, you would want the following:
function DoStuff `{ [CmdletBinding()] param () process { new-item Test -type Directory ` -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) }}
This covers -Verbose, -Verbose:$false, -Verbose:$true, and the case where the switch is not present at all.
Perhaps it sounds strange, but there isn't any easy way for a cmdlet to know its verbose or debug mode. Take a look at the related question:
How does a cmdlet know when it really should call WriteVerbose()?
One not perfect, but practically reasonable, option is to introduce your own cmdlet parameters (for example, $MyVerbose
and $MyDebug
) and use them in the code explicitly:
function DoStuff { [CmdletBinding()] param ( # Unfortunately, we cannot use Verbose name with CmdletBinding [switch]$MyVerbose ) process { if ($MyVerbose) { # Do verbose stuff } # Pass $MyVerbose in the cmdlet explicitly New-Item Test -Type Directory -Verbose:$MyVerbose }}DoStuff -MyVerbose
UPDATE
When we need only a switch (not, say, a verbosity level value) then the approach with $PSBoundParameters
is perhaps better than proposed in the first part of this answer (with extra parameters):
function DoStuff { [CmdletBinding()] param() process { if ($PSBoundParameters['Verbose']) { # Do verbose stuff } New-Item Test -Type Directory -Verbose:($PSBoundParameters['Verbose'] -eq $true) }}DoStuff -Verbose
It's all not perfect anyway. If there are better solutions then I would really like to know them myself.
There is no need. PowerShell already does this as the code below proves.
function f { [cmdletbinding()]Param() "f is called" Write-Debug Debug Write-Verbose Verbose}function g { [cmdletbinding()]Param() "g is called" f }g -Debug -Verbose
The output is
g is calledf is calledDEBUG: DebugVERBOSE: Verbose
It is not done as direct as passing -Debug to the next cmdlet though. It is done through the $DebugPreference and $VerbrosePreference variables. Write-Debug and Write-Verbose act like you would expect, but if you want to do something different with debug or verbose you can read here how to check for yourself.