Make Destructive PowerShell Cmdlets Opt-In with $PSDefaultParameterValues
Use $PSDefaultParameterValues to inject -WhatIf and -Confirm on destructive PowerShell cmdlets by default, making destructive operations opt-in without changing cmdlet code.
19 Aug 2026, 06:07 UTC

The problem: destructive commands run too easily in shared scripts
Shared automation scripts get copied, edited, and run by different people. A Remove-Item, Clear-Content, or Stop-Service that was safe in a test folder can delete production data when the path variable changes. Changing every cmdlet call is brittle. The useful takeaway is to make destructive operations opt-in by default for a session using $PSDefaultParameterValues, so WhatIf and Confirm are injected automatically without touching cmdlet code.
Desired outcome
For the current PowerShell session, any cmdlet matching a destructive name pattern requires explicit opt-out before it can change state. Operators see WhatIf output first, and can remove the default when they are ready for real execution. The setting is session scoped unless persisted, so it does not permanently alter behavior.
Prerequisites
PowerShell 3.0 or later is required. $PSDefaultParameterValues was introduced in PowerShell 3.0 and is a session scoped automatic variable.
Script execution policy must allow the profile or script that sets the defaults to run. The setting itself requires no elevated privileges, but the destructive cmdlets you protect will still require the normal file system or service permissions when finally executed.
Understand scope. $PSDefaultParameterValues lives only for the current session. If you set it in a profile it applies to every future interactive session. If you set it inside a script, it affects only that script run and any child scopes.
Focused procedure
Set defaults in the session you want to protect. Run this in an interactive console or at the top of a wrapper script before any destructive calls.
# View current defaults
Get-Variable PSDefaultParameterValues -ValueOnly
The variable is a hashtable. Keys are in the form 'CmdletName:ParameterName' or with wildcards 'CmdletName*:ParameterName'.
# Make all Remove* cmdlets WhatIf by default
$PSDefaultParameterValues['Remove*:WhatIf'] = $true
That entry applies to Remove-Item, Remove-ItemProperty, Remove-Module, and any other cmdlet whose name starts with Remove. The WhatIf parameter is common to cmdlets that support -WhatIf.
For confirmation prompts on cmdlets that support -Confirm:
$PSDefaultParameterValues['Stop-Service:Confirm'] = $true
You can combine patterns and parameters. Example for a more conservative set:
$PSDefaultParameterValues['Remove*:WhatIf'] = $true
$PSDefaultParameterValues['Clear*:WhatIf'] = $true
$PSDefaultParameterValues['Stop-Service:Confirm'] = $true
$PSDefaultParameterValues['*-Item:WhatIf'] = $true
Run a benign test command to verify injection. Use a path you control.
Remove-Item -Path 'C:\\Temp\\test.txt'
With the default in place the cmdlet should emit WhatIf style output describing the action it would take and should not perform the deletion. Remove the default for real execution only after review:
$PSDefaultParameterValues.Remove('Remove*:WhatIf')
Remove-Item -Path 'C:\\Temp\\test.txt'
Expected checks
Confirm the hashtable contains the intended keys.
Get-Variable PSDefaultParameterValues -ValueOnly
Check that a matching cmdlet respects the default. Execute a non-destructive test with WhatIf output visible. Verify the action is not performed.
Confirm normal operation resumes after removal. Remove the specific key from the hashtable and re-run the same command. The cmdlet should now behave without automatic WhatIf.
Recovery and limitations
Recovery is simple because the change is in memory. Clear the specific entry:
$PSDefaultParameterValues.Remove('Remove*:WhatIf')
Or restart the session to drop all defaults.
Limitations to plan for:
- Entries apply to all cmdlets matching the pattern in the current session, including third-party modules. A broad wildcard can cause unexpected WhatIf prompts for commands you did not intend to protect.
- Persistence via $PROFILE changes defaults for all future interactive sessions. Operators may be surprised by prompts they did not set.
- Wildcard patterns can be too broad. Remove* matches both Remove-Item and Remove-Computer. Test patterns carefully.
- WhatIf is not supported by every cmdlet. If a cmdlet does not implement -WhatIf, the default is silently ignored.
Practical way to check result: keep a small test block at the top of shared scripts that prints the current defaults and runs a harmless WhatIf command, so reviewers can see the safety net is active before the script proceeds.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.