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.