5

I'm writing a PowerShell Cmdlet and using WriteDebug, but I want to write an object which requires an extra API call, and I'd rather not make that call when debugging is turned off. How can I detect whether the Debug flag is set or not, so that I can skip this call to WriteDebug entirely?

For example, my WriteDebug call will look something like this:

WriteDebug(string.Format("Name : {0}", api.GetName(myobj)));

In that example, I want to avoid the call to api.GetName unless debugging is turned on.

Ricket
  • 33,368
  • 30
  • 112
  • 143
  • Based on [stej's answer to a similar question](http://stackoverflow.com/a/2777219/2495), I would guess there is no straightforward way to get the current value of `$DebugPreference` from a cmdlet. – Emperor XLII Jun 08 '12 at 13:07

4 Answers4

5

Just checking if the -Debug flag is set can be done with the code below, but it is not enough.

bool debug = false;
bool containsDebug = MyInvocation.BoundParameters.ContainsKey("Debug");
if (containsDebug)
    debug = ((SwitchParameter)MyInvocation.BoundParameters["Debug"]).ToBool();

PowerShell also allows you to set a global flag called $DebugPreference which the code above does not check. And calling a cmdlet from another cmdlet inherits these common parameters which is not inherited through the Debug flag as the code above checks. The code below will check $DebugPreference and solves those problems.

debug = (ActionPreference)GetVariableValue("DebugPreference") != ActionPreference.SilentlyContinue;

Unfortunately in contrary to a cmdlet in PowerShell you have to check both. So the final C# code is as below. I have also added the code for the Verbose common parameter as bonus. Be sure to inherit from PSCmdlet instead of Cmdlet to get to the GetVariableValue method.

bool debug = false;
bool containsDebug = MyInvocation.BoundParameters.ContainsKey("Debug");
if (containsDebug)
    debug = ((SwitchParameter)MyInvocation.BoundParameters["Debug"]).ToBool();
else
    debug = (ActionPreference)GetVariableValue("DebugPreference") != ActionPreference.SilentlyContinue;

bool verbose = false;
bool containsVerbose = MyInvocation.BoundParameters.ContainsKey("Verbose");
if (containsVerbose)
    verbose = ((SwitchParameter)MyInvocation.BoundParameters["Verbose"]).ToBool();
else
    verbose = (ActionPreference)GetVariableValue("VerbosePreference") != ActionPreference.SilentlyContinue; 
Community
  • 1
  • 1
Lars Truijens
  • 42,837
  • 6
  • 126
  • 143
4

Try this:

$Debug = $psboundparameters.debug.ispresent


if ($Debug){
  Write-Debug(string.Format("Name : {0}", api.GetName(myobj))
  }
mjolinor
  • 66,130
  • 7
  • 114
  • 135
  • +1 -have you a good link that explain this kind of awesome use of $psboundparameters? thanks! – CB. Mar 27 '12 at 19:50
  • Thanks! Unfortunately, no. I just ran up a test functions and checked to see how the -debug switch showed up in the binding. – mjolinor Mar 27 '12 at 20:00
  • How would I access this from C#? I'm writing a C# class that extends [PSCmdlet](http://msdn.microsoft.com/en-us/library/system.management.automation.pscmdlet(v=vs.85).aspx), not a script cmdlet. – Ricket Mar 27 '12 at 20:27
  • I'm afraid I don't know that. I suspect it's going to involve something called a "variabletoken", but won't speculate further. – mjolinor Mar 27 '12 at 22:45
  • 1
    $psboundparameters usage is discribed in [about_Automatic_Variables](http://technet.microsoft.com/en-us/library/dd347675.aspx) – JPBlanc Mar 28 '12 at 03:46
  • 3
    The problem with this approach is that the Debug setting is inherited, but its presence in psboundparameters is not inherited. (Sorry, I don't have anything constructive to contribute.) – OldFart Mar 28 '12 at 14:53
  • I understood the question to be how to control writing a debug message only if -debug was explicitly specified on this function, not just enabled by inheritance. – mjolinor Mar 28 '12 at 15:04
3

Experimentation indicates you might want to look at the $DebugPreference variable. I tried it with advanced functions, but it probably works just as well in a cmdlet.

Try the following sequence of commands:

function f { [cmdletbinding()]Param() $DebugPreference }
function g { [cmdletbinding()]Param() f }
f
f -Debug
g
g -Debug
OldFart
  • 2,411
  • 15
  • 20
2

To access the Debug flag from C# you should be able to do essentially the same thing as mjolinor suggests:

if (this.MyInvocation.BoundParameters.ContainsKey("Debug"))
{
    ... do something ...
}

However, note that you can specify the debug parameter with a value of false:

MyCmdlet -Debug:$false

To handle this case, you probably want to add something like this (from within the PSCmdlet):

bool debug = MyInvocation.BoundParameters.ContainsKey("Debug") &&
             ((SwitchParameter)MyInvocation.BoundParameters["Debug"]).ToBool();

In C# BoundParameters is a dictionary, so you could also use TryGetValue(), but note that the value of a switch (like Debug) is a SwitchParameter not a bool.

for further information see the following:

StephenD
  • 3,662
  • 1
  • 19
  • 28