Share via


Powershell Parameters 2: common parameters.

In the previous post I talked about the template I have for many of my PowerShell functions. And I've talked before about adding support for ShouldProcess to functions which change the state of the system (  that allows  –confirm, -prompt, –whatif and –verbose switches). Since then I’ve learnt that functions can identify the level of impact they have – this ties into the $confirmPreference variable to turn confirmation prompts on without needing to specify them explicitly. Adding shouldProcess support turns my function template into this:
Function Stop-VM{           [CmdletBinding( SupportsShouldProcess=$True, ConfirmImpact='High') ] ``   Param( [parameter(Mandatory = $true, ValueFromPipeline = $true)]$VM ,            $Server = "." )   ``` Process{ if ($VM –is  [String]) {$VM = GetVM –vm $vm –server $server}           if ($VM –is  [array]) {$VM | foreach-object {Stop-VM –vm $_ –server $server}}           if ($VM –is  [System.Management.ManagementObject] –and $pscmdlet.shouldProcess($vm.ElementName, "Power-Off VM without Saving")) {               ``` $vm.RequestStateChange(3)            } }} `

There is one nuisance when dealing with more than one VM: we will get the following message for every VM

 Confirm

Are you sure you want to perform this action?

Performing operation "Power-Off VM without Saving" on Target "London-DC".

[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): n

even if we select “Yes to all” or “No to all”.
Each recursive call to Stop-VM has its own instance of $psCMDLET. And if confirmImpact is set to High, that will cause a script to stop and prompt. Jason Shirk, one of the active guys in our internal PowerShell alias pointed out first you can have a –force switch to prevent the prompt appearing and secondly you don’t need to use the functions’ OWN instances of $psCMDLET: why not pass one instance around? So my function template morphed into the following:

Function Stop-VM{           `` [CmdletBinding( SupportsShouldProcess=$True, ConfirmImpact='High')]  ``    Param( [parameter(Mandatory = $true, ValueFromPipeline = $true)]$VM ,            $Server = "." ,            $PSC,             [Switch] $force) ``  Process{  if ($psc -eq $null) {$psc = $pscmdlet } `` if (-not $PSBoundParameters.psc) {$PSBoundParameters.add("psc",$psc)}              if ($VM –is [String])  {$VM = GetVM –vm $vm –server $server}            if ($VM –is [array])   {[Void]$PSBoundParameters.Remove("VM")                                    $VM | ForEach-object {Stop-Vm -VM $_ @PSBoundParameters}}           ```  if ($VM -is [System.Management.ManagementObject]                   –and ($force -or $psc.shouldProcess($vm.ElementName, "Power-Off VM without Saving"))){                   $vm.RequestStateChange(3)            } ``` }} `

So now the first function called sets $PSC, which is passed to all other functions - in this case recursive calls to this function – which use it in place of their instance of $psCmdlet. And –force is there to trump everything.