Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DebugPreference, ShouldProcess and ConfirmImpact

Tags:

powershell

I don't understand why when I pass -Debug to my script, it asks for confirmation, unless I also pass -Confirm:$False (or set ConfirmImpact='none'). I cannot find any documentation that states DebugPreference interacts with ShouldProcess.

test.ps1

[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='Medium')]
param()
Write-Host "`n--- DEBUGGING STATE ---"
Write-Host "DebugPreference   = $DebugPreference"
Write-Host "WhatIfPreference  = $WhatIfPreference"
Write-Host "ConfirmPreference = $ConfirmPreference"
Write-Host "-------------------------`n"

if ($PSCmdlet.ShouldProcess("Thing", "Do something on")) {
    Write-Host "DID SOMETHING"
 }

Tests:

PS > test.ps1

--- DEBUGGING STATE ---
DebugPreference   = SilentlyContinue
WhatIfPreference  = False
ConfirmPreference = High
-------------------------

DID SOMETHING



PS > test.ps1 -Debug

--- DEBUGGING STATE ---
DebugPreference   = Inquire
WhatIfPreference  = False
ConfirmPreference = High
-------------------------


Confirm
Are you sure you want to perform this action?
Performing operation "Do something on" on Target "Thing".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):



PS > test.ps1 -Debug -WhatIf

--- DEBUGGING STATE ---
DebugPreference   = Inquire
WhatIfPreference  = True
ConfirmPreference = High
-------------------------

What if: Performing operation "Do something on" on Target "Thing".



PS > test.ps1 -Debug -Confirm:$False

--- DEBUGGING STATE ---
DebugPreference   = Inquire
WhatIfPreference  = False
ConfirmPreference = None
-------------------------

DID SOMETHING
like image 340
Bangaio Avatar asked Aug 28 '26 14:08

Bangaio


1 Answers

It is indeed curious that passing -Debug would implicitly behave as if -Confirm had also been specified, and this coupling smells like a bug or a design flaw.

Here's a workaround that bypasses the $PSCmdlet.ShouldProcess() call if -Debug is passed, except if -Confirm (implicitly the same as -Confirm:true) is also passed or if $ConfirmPreference was set to 'Medium' or 'Low' before calling the script and except if -WhatIf is also passed.

[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
param()

# ...

$debugWithoutPrompt = 
  $PSBoundParameters['Debug'] -and
  $(
    if (-not $PSBoundParameters.ContainsKey('Confirm')) { $ConfirmPreference -in 'High', 'None' } 
    else { -not $PSBoundParameters['Confirm'] }
  ) -and
  -not $WhatIfPreference

if ($debugWithoutPrompt -or $PSCmdlet.ShouldProcess('Thing', 'Do something on')) {
  Write-Host 'DID SOMETHING'
}

Note:

  • Curiously even though passing -Confirm:$false, i.e. the negated form of the common -Confirm parameter, in advanced functions or scripts, sets a function-local copy of the $ConfirmPreference preference variable to 'None', which is effective in suppressing a confirmation prompt in combination with -Debug, setting $ConfirmPreference = 'None' manually, whether in the caller's scope before calling the script or inside the script, does not work (it only works without -Debug).

  • Similarly, passing common -WhatIf parameter-WhatIf gets translated to a function-local copy of the $WhatIfPreference preference variable with value $true (unless negated). In order to preserve -WhatIf functionality, the $PSCmdlet.ShouldProcess() call must not be bypassed if -WhatIf was passed or $WhatIfPreference = $true was set before calling the script; both conditions can therefore be detected with a Boolean test of $WhatIfPreference

  • By questionable design, in Windows PowerShell (the legacy, ships-with-Windows, Windows-only edition of PowerShell whose latest and last version is 5.1), the common -Debug parameter gets translated to a function-local copy of the $DebugPreference preference variable with a value of 'Inquire', which causes every call to Write-Debug to present an interactive prompt.
    This unhelpful behavior has been fixed in PowerShell (Core) 7.

    • You can fix the questionable Windows PowerShell behavior by placing the following after your script's param() block:

      if ($PSBoundParameters.ContainsKey('Debug') -and
          $PSBoundParameters['Debug']) { 
            $DebugPreference = 'Continue'
      }
      
like image 93
mklement0 Avatar answered Aug 31 '26 05:08

mklement0



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!