9

How can I check in PowerShell if my script is running in debug mode? I am currently debugging in Visual Studio 2015 with PowerShell Tools installed.

A portion of the script sends an e-mail using Send-MailMessage. I would like to do something similar to below.

If (Debug)
{
    $messageProperties.To = "$env:username@company.com"
}
Else
{
    $messageProperties.To = "prodmailbox@company.com"
}

I know in C# that I can do something like the below. I would like to know how this is handled in PowerShell.

#if DEBUG
    // Debug code
#endif
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ryan Gates
  • 4,501
  • 6
  • 50
  • 90
  • Rather than guessing, can you just pass a switch to the script telling it the current state (ie. "debug" or "release"). You can set a default for the switch to "Debug". – rrirower Feb 17 '16 at 16:58
  • Possible duplicate of [In a Cmdlet, how can I detect if the Debug flag is set?](http://stackoverflow.com/questions/9895163/in-a-cmdlet-how-can-i-detect-if-the-debug-flag-is-set) – Michael Freidgeim Dec 23 '16 at 11:30

3 Answers3

7

Here's a function which allows you easily check; along with a few options to alter the behaviour.

function Test-Debug {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [switch]$IgnorePSBoundParameters
        ,
        [Parameter(Mandatory = $false)]
        [switch]$IgnoreDebugPreference
        ,
        [Parameter(Mandatory = $false)]
        [switch]$IgnorePSDebugContext
    )
    process {
        ((-not $IgnoreDebugPreference.IsPresent) -and ($DebugPreference -ne "SilentlyContinue")) -or
        ((-not $IgnorePSBoundParameters.IsPresent) -and $PSBoundParameters.Debug.IsPresent) -or
        ((-not $IgnorePSDebugContext.IsPresent) -and ($PSDebugContext))
    }
}

Here's some code to demonstrate output in certain scenarios:

#region 'Test Functions'
function Test-InheritExplicit {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [switch]$IgnorePSBoundParameters
        ,
        [Parameter(Mandatory = $false)]
        [switch]$IgnoreDebugPreference
        ,
        [Parameter(Mandatory = $false)]
        [switch]$IgnorePSDebugContext
    )
    process {
        #if we weren't splatting all vars over, we could use this trick:
        #[switch]$DebugCopy = $PSBoundParameters.Debug
        #Test-Debug -Debug:$DebugCopy
        Test-Debug @PSBoundParameters
    }
}

function Test-InheritImplicit {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [switch]$IgnorePSBoundParameters
        ,
        [Parameter(Mandatory = $false)]
        [switch]$IgnoreDebugPreference
        ,
        [Parameter(Mandatory = $false)]
        [switch]$IgnorePSDebugContext
    )
    process {
        Test-Debug -IgnorePSBoundParameters:$IgnorePSBoundParameters -IgnorePSDebugContext:$IgnorePSDebugContext -IgnoreDebugPreference:$IgnoreDebugPreference
    }
}
#endregion 'Test Functions'

#region 'Test Cases'
[hashtable[]]$testCases = 0..15 | %{
    [hashtable]$new = @{}
    if ($_ -band 1) {$new.Debug = [switch]$true}
    if ($_ -band 2) {$new.IgnorePSBoundParameters = [switch]$true}            
    if ($_ -band 4) {$new.IgnoreDebugPreference = [switch]$true}
    if ($_ -band 8) {$new.IgnorePSDebugContext = [switch]$true}
    $new
}

[int]$t = 0
$testCases | %{
    [hashtable]$testCase = $_
    (New-Object -TypeName PSObject -Property @{
        TestId = ++$t
        Debug = [bool]$_.Debug
        IgnorePSBoundParameters = [bool]$_.IgnorePSBoundParameters
        IgnoreDebugPreference = [bool]$_.IgnoreDebugPreference
        IgnorePSDebugContext = [bool]$_.IgnorePSDebugContext
        TD = (Test-Debug @testCase)
        TIE = (Test-InheritExplicit @testCase)
        TII = (Test-InheritImplicit @testCase)
    })
} | Format-Table  TestId, Debug, IgnorePSBoundParameters, IgnoreDebugPreference, IgnorePSDebugContext, TD, TIE, TII -AutoSize

Here's the output from the above:

TestId Debug IgnorePSBoundParameters IgnoreDebugPreference IgnorePSDebugContext    TD   TIE   TII
------ ----- ----------------------- --------------------- --------------------    --   ---   ---
     1 False                   False                 False                False False False False
     2  True                   False                 False                False  True  True  True
     3 False                    True                 False                False False False False
     4  True                    True                 False                False  True  True  True
     5 False                   False                  True                False False False False
     6  True                   False                  True                False  True  True False
     7 False                    True                  True                False False False False
     8  True                    True                  True                False False False False
     9 False                   False                 False                 True False False False
    10  True                   False                 False                 True  True  True  True
    11 False                    True                 False                 True False False False
    12  True                    True                 False                 True  True  True  True
    13 False                   False                  True                 True False False False
    14  True                   False                  True                 True  True  True False
    15 False                    True                  True                 True False False False
    16  True                    True                  True                 True False False False
JohnLBevan
  • 22,735
  • 13
  • 96
  • 178
4

"Debugged" in PowerShell could mean several things. 1) The program is running under a debugger, 2) The cmdlet/function is passed -Debug flag or $DebugPreferences is not SilentlyContinue 3) PowerShell tracing is on, 4) Set-PSDebug was used to toggle tracing (a different kind of tracing than #3).

If you haven't chosen one of these already, I suggest you pick #2. It is straightforward (check if -Debug is in PSBoundVariables or value of $DebugPreferences is not SilentlyContinue). It supports Write-Debug cmdlet. In general terms, it is the PowerShell-ish way to toggle debug output.

If you really need #1, then as this page explains, implementing a PowerShell debugger at its core is handling two events (Debugger.BreakpointUpdated and Debugger.DebuggerStop), so you need to see if there is a handler for these events.

If you need #4, you'll probably need to access private data. The only PowerShell 3.0 command with PSDebug as the noun is Set-PSDebug, which means there isn't a cmdlet to return the state of PSDebug.

If you need #3, then the situation is similar to #4. There aren't cmdlets to return information of what's being traced.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Χpẘ
  • 3,403
  • 1
  • 13
  • 22
  • Can you provide an example in a PowerShell script for each of these options? – Ryan Gates Feb 17 '16 at 16:42
  • 1
    Let me suggest this, more in keeping with the spirit of SO (as a programmer to programmer resource for solving specific programming problems): using a web search to find examples if necessary, write a script. If you have problems with the script then add it to the OP and update your question. – Χpẘ Feb 17 '16 at 17:04
1

Example template script with backward compatibility (and a little commenting)

# turn regular script into advanced script by adding the cmdletbinding attribute and its required param()
[CmdletBinding()]
Param()

$DebugPreferenceWas = $DebugPreference

# $debugPreference is default to "SilentlyContinue"
# if -debug argument passed, we get "$DebugPreference=Inquire"
if ($DebugPreference -ne "SilentlyContinue" -And $PSVersionTable.PSVersion.Major -lt 6) {
    # note: for backward compatibility set $DebugPreference='Continue'
    #       prior to PowerShell 6, we would have to answer a question for each Debug message, this change in v6
    Write-Output "Backward compatibility, update DebugPreference"
    $DebugPreference = 'Continue'
    Write-Output "DebugPreference was: $DebugPreferenceWas, changed to: $DebugPreference"
}

Write-Debug "this line will only print if -Debug was passed to the script"

Write-Output "script ran, exiting"

So, like we do the check, you could do something like:

[CmdletBinding()]
Param()

# ... some code here creating variables or whatnot ...

if ($DebugPreference -ne "SilentlyContinue") {
  # in debug
  $messageProperties.To = "$env:username@company.com"
} else {
  # not debug
  $messageProperties.To = "prodmailbox@company.com"
}
silentpete
  • 350
  • 2
  • 7