27

我有一个支持-WhatIf&-Confirm参数的 PowerShell 脚本 cmdlet。

它通过$PSCmdlet.ShouldProcess()在执行更改之前调用该方法来完成此操作。
这按预期工作。

我遇到的问题是我的 Cmdlet 是通过调用其他 Cmdlet 来实现的,并且-WhatIfor-Confirm参数没有传递给我调用的 Cmdlet。

如何将值传递给从 Cmdlet 调用-WhatIf-ConfirmCmdlet?

例如,如果我的 Cmdlet 是Stop-CompanyXyzServices并且它用于Stop-Service实现其操作。

如果-WhatIf传递给Stop-CompanyXyzServices我希望它也传递给停止服务。

这可能吗?

4

6 回答 6

19

显式传递参数

您可以使用and变量传递-WhatIfand-Confirm参数。以下示例通过参数 splatting实现了这一点:$WhatIfPreference$ConfirmPreference

if($ConfirmPreference -eq 'Low') {$conf = @{Confirm = $true}}

StopService MyService -WhatIf:([bool]$WhatIfPreference.IsPresent) @conf

$WhatIfPreference.IsPresentTrue如果在-WhatIf包含功能上使用开关,将是。使用-Confirm包含功能上的开关暂时设置$ConfirmPreferencelow

隐式传递参数

既然-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在确认首选项为“低”时设置开关。

于 2011-08-24T19:34:02.257 回答
7

经过一番谷歌搜索后,我想出了一个很好的解决方案,可以将常用参数传递给调用的命令。您可以使用 @ 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 之类的参数传递给脚本中调用的命令,它们尊重调用者的意图。

于 2011-11-03T18:29:19.387 回答
3

这是基于@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. 希望这可以帮助某人。

于 2011-08-24T18:26:54.963 回答
1

根据@manojlds 评论更新

将 $WhatIf 和 $Confirm 转换为布尔值并将值传递给底层 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)
        }                       
    }
}
于 2011-08-25T08:52:33.410 回答
0

只是为了让您不会被这个问题和这里的答案绕着街区跑几个小时,我建议您改为阅读这篇文章:

https://powershellexplained.com/2020-03-15-Powershell-shouldprocess-whatif-confirm-shouldcontinue-everything/#suppressing-nested-confirm-prompts

这里提供的答案在许多情况下都不起作用,我认为人们在不了解基本原理的情况下实施这里的答案是危险的。

以下是如何破解它以跨脚本模块工作: 在此处输入图像描述

于 2022-02-27T19:41:05.823 回答
0
OtherCmdlet -WhatIf:$WhatIfPreference
于 2022-03-01T22:36:23.700 回答