$ PSCmdlet.ShouldProcess状态在两次调用之间存储在哪里(以及如何将其重置)?

时间:2019-06-07 01:09:27

标签: powershell

考虑以下人为设计的示例:

function Test-ProcessContinue {
    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')]
    Param()

    for ($i = 1; $i -le 3; $i++) {
        if ($PSCmdlet.ShouldProcess("$i", "Process")) {
            Write-Output "Processing $i"
        }
        else {
            Write-Verbose "No chosen"
        }
    }

    for ($i = 1; $i -le 3; $i++) {
        if ($PSCmdlet.ShouldProcess("$i", "Process")) {
            Write-Output "Processing $i"
        }
        else {
            Write-Verbose "No chosen"
        }
    }

    $yta = $false; $nta = $false
    for ($i = 1; $i -le 3; $i++) {
        if ($PSCmdlet.ShouldContinue("$i", "Continue", [ref]$yta, [ref]$nta) -or $yta) {
            Write-Output "Continuing with $i"
        }
        elseif ($nta) {
            Write-Verbose "No to all chosen"
            break
        }
        else {
            Write-Verbose "No chosen"
        }
    }
}

...及其潜在输出之一:

PS C:\> Test-ProcessContinue -Verbose

Confirm
Are you sure you want to perform this action?
Performing the operation "Process" on target "1".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): a
Processing 1
Processing 2
Processing 3
Processing 1
Processing 2
Processing 3

Continue
1
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): a
Continuing with 1
Continuing with 2
Continuing with 3

ShouldContinue循环(第三个for循环)的情况下,我可以看到两个副引用布尔参数的重载负责存储最终用户是否选择对这两个布尔值全部同意全部拒绝

但是,对于两个ShouldProcess块(前两个for循环),该状态如何保存?

尤其是在前两个ShouldProcess块之间,我如何检查是否指定了全部同意全部拒绝和/或指定了什么?我是否需要重置或清除以便使第二个ShouldProcess块再次要求确认?

((ShouldContinue胜过ShouldProcess是用于细粒度控制的选项,但它似乎失去了对[CmdletBinding(SupportsShouldProcess=$true)]的本机/内置支持

2 个答案:

答案 0 :(得分:4)

首先,我将向$PSCmdlet.ShouldContinue致辞。基本上,这是一种提示自己输入 的方法,而与“确认”偏好设置无关。

另一方面,

$PSCmdlet.ShouldProcess并不总是提示。它考虑了ConfirmImpact(您将其设置为High)和$ConfirmPreference自动变量,其默认值为High。有效值为NoneLowMediumHigh,它们的意思是指示更改有多大的影响,因此$ConfirmPreference' s的值等于或小于命令的ConfirmImpact的值,则将提示ShouldProcess

我知道这不是您的直接问题,但是背景对于回答您应该做的事情很重要。

直接的问题:“答案存储在哪里?”答案很无聊:it's stored in an internal variable in the class that defines the ShouldProcess method

因此,不幸的是,您无法自己解决问题。

但是,这使我们回到.ShouldContinue,它可以获取这些引用并为您存储这些值,因此当您需要这些值并希望能够与它们做出决定时,应使用{{ 1}}。

但是,您应该同时使用两者。因为他们做不同的事情。

.ShouldContinue不仅负责确认提示,还负责处理.ShouldProcess / -WhatIf;当您说命令$WhatIfPreference时,也表示它支持SupportsShouldProcess。如果您不使用-WhatIf,则会遇到以下情况:命令看起来很安全,但实际上仍然会采取措施。

因此,类似这样的模式将覆盖您的基础:

.ShouldProcess

此问题可以归结为您确定的影响和偏好。如果这些命令排成一行,或者用户用if ($PSCmdet.ShouldProcess('thing', 'do')) { if ($PSCmdlet.ShouldContinue('prompt')) { # do it } } 调用了您的命令,您将提示两次:一次在-Confirm中,然后再次在.ShouldProcess中。

不幸的是,这种糟透了。

我写了一篇似乎可以解决此问题的东西。它首先基于一个函数,该函数使您可以运行带有确认的任意脚本块,以便在抑制其提示的同时仍可以运行.ShouldContinue

然后,它还会尝试计算是否需要提示,然后有选择地调用.ShouldProcess。我没有演示存储或重置yesToAll和noToAll变量,因为您已经知道如何做到这一点。

这主要是为了演示一种模式,该模式可用于遵循标准的确认提示语义,具有可发现性,支持.ShouldContinue参数,-Confirm$ConfirmPreference,同时保持支持ConfirmImpact-Verbose

-WhatIf

调用:

function Test-Should {
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    param()

    Begin {
        $local:ShouldConfirm = $ConfirmPreference -ne [System.Management.Automation.ConfirmImpact]::None -and 
                               $ConfirmPreference -le [System.Management.Automation.ConfirmImpact]::High # hard coded :(

        function Invoke-CommandWithConfirmation {
            [CmdletBinding(SupportsShouldProcess)]
            param(
                [Parameter(Mandatory)]
                [ScriptBlock]
                $ScriptBlock
            )

            Invoke-Command -NoNewScope -ScriptBlock $ScriptBlock
        }
    }

    Process {
        if (Invoke-CommandWithConfirmation -ScriptBlock { $PSCmdlet.ShouldProcess('target', 'action') } -Confirm:$false ) {
            if (-not $local:ShouldConfirm -or $PSCmdlet.ShouldContinue('query', 'caption')) {
                'Hi' | Write-Host
                'Hello' | Write-Verbose
            }
        }
    }
}

以此类推,使用不同的Test-Should Test-Should -Confirm Test-Should -Confirm:$false Test-Should -Verbose Test-Should -Verbose -WhatIf Test-Should -WhatIf -Confirm Test-Should -WhatIf -Confirm:$false 值和不同的命令$ConfirmPreference值。

令人讨厌的一件事是我标记为硬编码的值:它必须与您设置为该命令的确认影响的值匹配。

It turns out it's kind of a pain in the ass to get at that value programmatically,但也许您可以以某种方式进行操作。

答案 1 :(得分:0)

这主要是@briantist 答案的扩展,但我一直在努力解决如何完全实现这一问题,但我已经按照我想要的方式工作,并希望分享,以防其他人与我有类似的目标.我希望把它变成一个完整的类,为我完成所有这些,但只是小步。

std::string&