我有一个支持-WhatIf
&的PowerShell脚本cmdlet。 -Confirm
个参数。
通过在执行更改之前调用$PSCmdlet.ShouldProcess()
方法来实现此目的
这按预期工作。
我遇到的问题是我的Cmdlet是通过调用其他Cmdlet实现的,而-WhatIf
或-Confirm
参数不会传递给我调用的Cmdlet。
如何将-WhatIf
和-Confirm
的值传递给我从Cmdlet调用的Cmdlet?
例如,如果我的Cmdlet是Stop-CompanyXyzServices
并且它使用Stop-Service
来实现其操作。
如果-WhatIf
传递给Stop-CompanyXyzServices
我希望它也传递给停止服务。
这可能吗?
答案 0 :(得分:14)
明确传递参数
您可以使用-WhatIf
和-Confirm
变量传递$WhatIfPreference
和$ConfirmPreference
参数。以下示例使用parameter splatting:
if($ConfirmPreference -eq 'Low') {$conf = @{Confirm = $true}}
StopService MyService -WhatIf:([bool]$WhatIfPreference.IsPresent) @conf
如果在包含的函数上使用$WhatIfPreference.IsPresent
开关,则 True
将为-WhatIf
。使用包含该函数的-Confirm
开关会暂时将$ConfirmPreference
设置为low
。
隐式传递参数
由于-Confirm
和-WhatIf
会自动暂时设置$ConfirmPreference
和$WhatIfPreference
变量,是否有必要传递它们?
考虑一下这个例子:
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
会从True
ShouldProcess()
即使我没有通过切换, ShouldTestCaller -Confirm
也会出现确认提示。
修改强>
@manojlds回答让我意识到我的解决方案总是将$ConfirmPreference
设置为'低'或'高'。如果确认首选项为“低”,我已将代码更新为仅设置-Confirm
开关。
答案 1 :(得分:6)
经过一些谷歌搜索后,我想出了一个很好的解决方案,用于将常用参数传递给被调用的命令。您可以使用@splatting运算符传递传递给命令的所有参数。例如,如果
Start-Service -Name ServiceAbc @PSBoundParameters
位于脚本的主体中,powershell会将传递给脚本的所有参数传递给Start-Service命令。唯一的问题是,如果你的脚本包含一个-Name参数,它也会被传递,PowerShell会抱怨你包含-Name参数两次。我编写了以下函数将所有常用参数复制到新字典中,然后我将其展开。
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
}
}
最终结果是将-Verbose之类的参数传递给脚本中调用的命令,并且他们遵守调用者的意图。
答案 2 :(得分:2)
这是一个完整的解决方案,基于@Rynant和@Shay Levy的答案:
function Stop-CompanyXyzServices
{
[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]
Param(
[Parameter(
Position=0,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true
)]
[string]$Name
)
process
{
if($PSCmdlet.ShouldProcess($env:COMPUTERNAME,"Stop XYZ services '$Name'")){
ActualCmdletProcess
}
if([bool]$WhatIfPreference.IsPresent){
ActualCmdletProcess
}
}
}
function ActualCmdletProcess{
# add here the actual logic of your cmdlet, and any call to other cmdlets
Stop-Service $name -WhatIf:([bool]$WhatIfPreference.IsPresent) -Confirm:("Low","Medium" -contains $ConfirmPreference)
}
我们必须分别查看-WhatIf
是否单独传递,以便将whatif传递给各个cmdlet。 ActualCmdletProcess
基本上是一个重构,因此您不会再为WhatIf
再次调用同一组命令。希望这有助于某人。
答案 3 :(得分:0)
根据@manojlds评论更新
将$ WhatIf和$ Confirm转换为Boolean并将值传递给基础cmdlet:
function Stop-CompanyXyzServices
{
[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')]
Param(
[Parameter(
Position=0,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true
)]
[string]$Name
)
process
{
if($PSCmdlet.ShouldProcess($env:COMPUTERNAME,"Stop service '$Name'"))
{
Stop-Service $name -WhatIf:([bool]$WhatIf) -Confirm:([bool]$confirm)
}
}
}