Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you support PowerShell's -WhatIf & -Confirm parameters in a Cmdlet that calls other Cmdlets?

I have a PowerShell script cmdlet that supports the -WhatIf & -Confirm parameters.

It does this by calling the $PSCmdlet.ShouldProcess() method before performing the change.
This works as expected.

The problem I have is that my Cmdlet is implemented by calling other Cmdlets and the -WhatIf or -Confirm parameters are not passed along to the Cmdlets I invoke.

How can I pass along the values of -WhatIf and -Confirm to the Cmdlets I call from my Cmdlet?

For example, if my Cmdlet is Stop-CompanyXyzServices and it uses Stop-Service to implement its action.

If -WhatIf is passed to Stop-CompanyXyzServices I want it to also be passed to Stop-Service.

Is this possible?

like image 301
Dan Finucane Avatar asked Aug 24 '11 18:08

Dan Finucane


People also ask

How do you use PowerShell help?

To get help for a PowerShell provider, type Get-Help followed by the provider name. For example, to get help for the Certificate provider, type Get-Help Certificate . You can also type help or man , which displays one screen of text at a time.

How does PowerShell work?

PowerShell automates many tasks, from the complete roll out of a new server in a virtual environment, to the configuration of new mailboxes in Microsoft 365 and a host of additional functions in-between. In their simplest form, PowerShell scripts are a collection of PowerShell commands.

What is PowerShell support?

PowerShell is a cross-platform task automation solution made up of a command-line shell, a scripting language, and a configuration management framework. PowerShell runs on Windows, Linux, and macOS.

How do I get the PowerShell Commandlet help?

The Get-Help cmdlet displays information about Windows PowerShell concepts and commands, including cmdlets, functions, CIM commands, workflows, providers, aliases and scripts. To get help for a Windows PowerShell command, type `Get-Help` followed by the command name, such as: `Get-Help Get-Process`.


2 Answers

Passing parameters explicitly

You can pass the -WhatIf and -Confirm parameters with the $WhatIfPreference and $ConfirmPreference variables. The following example achieves this with parameter splatting:

if($ConfirmPreference -eq 'Low') {$conf = @{Confirm = $true}}  StopService MyService -WhatIf:([bool]$WhatIfPreference.IsPresent) @conf 

$WhatIfPreference.IsPresent will be True if the -WhatIf switch is used on the containing function. Using the -Confirm switch on the containing function temporarily sets $ConfirmPreference to low.

Passing parameters implicitly

Since the -Confirm and -WhatIf temporarily set the $ConfirmPreference and $WhatIfPreference variables automatically, is it even necessary to pass them?

Consider the example:

function ShouldTestCallee {     [cmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]      param($test)      $PSCmdlet.ShouldProcess($env:COMPUTERNAME,"Confirm?") }   function ShouldTestCaller {     [cmdletBinding(SupportsShouldProcess=$true)]     param($test)      ShouldTestCallee }  $ConfirmPreference = 'High' ShouldTestCaller ShouldTestCaller -Confirm 

ShouldTestCaller results in True from ShouldProcess()

ShouldTestCaller -Confirm results in an confirm prompt even though I didn't pass the switch.

Edit

@manojlds answer made me realize that my solution was always setting $ConfirmPreference to 'Low' or 'High'. I have updated my code to only set the -Confirm switch if the confirm preference is 'Low'.

like image 187
Rynant Avatar answered Oct 02 '22 22:10

Rynant


After some googling I came up with a good solution for passing common parameters along to called commands. You can use the @ splatting operator to pass along all the parameters that were passed to your command. For example, if

Start-Service -Name ServiceAbc @PSBoundParameters

is in the body of your script powershell will pass all the parameters that were passed to your script to the Start-Service command. The only problem is that if your script contains say a -Name parameter it will be passed too and PowerShell will complain that you included the -Name parameter twice. I wrote the following function to copy all the common parameters to a new dictionary and then I splat that.

function Select-BoundCommonParameters {     [CmdletBinding()]     param(         [Parameter(Mandatory=$true)]         $BoundParameters     )     begin     {         $boundCommonParameters = New-Object -TypeName 'System.Collections.Generic.Dictionary[string, [Object]]'     }     process     {         $BoundParameters.GetEnumerator() |             Where-Object { $_.Key -match 'Debug|ErrorAction|ErrorVariable|WarningAction|WarningVariable|Verbose' } |             ForEach-Object { $boundCommonParameters.Add($_.Key, $_.Value) }          $boundCommonParameters     } } 

The end result is you pass parameters like -Verbose along to the commands called in your script and they honor the callers intention.

like image 30
Dan Finucane Avatar answered Oct 02 '22 22:10

Dan Finucane