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

标签 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 循环)的情况下,我可以看到带有两个按引用 bool 参数的重载负责存储是否最终用户在这两个 bool 值中选择了Yes to AllNo to All

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

特别是,在前两个 ShouldProcess block 之间,我如何检查是否指定了Yes to AllNo to All 并且/或者我需要重置或清除什么才能使第二个 ShouldProcess block 再次请求确认?

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

最佳答案

首先,我将介绍 $PSCmdlet.ShouldContinue。这基本上是一种自己提示的方式,无论确认首选项如何。

$PSCmdlet.ShouldProcess 另一方面,并​​不总是提示。它考虑了 ConfirmImpact(您设置为 High)和 $ConfirmPreference 自动变量,默认为 High。有效值为 NoneLowMediumHigh,用于指示影响程度有变化,所以当 $ConfirmPreference 的值等于或小于命令的 ConfirmImpact 值时,ShouldProcess 将提示。

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

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

所以,不,不幸的是,你不能自己得到它。

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

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

.ShouldProcess不仅负责确认提示,还负责处理-WhatIf/$WhatIfPreference;当您说您的命令 SupportsShouldProcess 时,您也表示它支持 -WhatIf。如果您不使用 .ShouldProcess,您将遇到这样一种情况:命令看似安全,但实际上无论如何都会执行操作。

所以像这样的模式将覆盖你的基地:

if ($PSCmdet.ShouldProcess('thing', 'do')) {
    if ($PSCmdlet.ShouldContinue('prompt')) {
        # do it
    }
}

这个问题可以追溯到您确认的影响和偏好。如果这些排队,或者如果用户使用 -Confirm 调用您的命令,您将提示两次:一次在 .ShouldProcess 中,然后在 中再次提示.ShouldContinue.

不幸的是,这种情况很糟糕。

我写了一个似乎可以解决这个问题的东西。它首先基于一个函数,该函数允许您在确认后运行任意脚本 block ,这样您仍然可以运行 .ShouldProcess,同时抑制其提示。

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

这主要是为了演示可用于遵守标准确认提示语义的模式,具有可发现性,支持 -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 的值不同,命令的ConfirmImpact 的值也不同。

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

It turns out it's kind of a pain in the ass to get at that value programmatically ,但也许您可以通过某种方式解决这个问题。

关于powershell - $PSCmdlet.ShouldProcess 状态在调用之间存储在哪里(以及如何重置)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56486821/

相关文章:

powershell - 用于构建服务器的 Azure 凭据

用于将组从静态更改为动态的 Powershell AzureAD 脚本

powershell - 使用 powershell 在 AD 中获取组织职位

azure - 使用逻辑应用创建具有关键字 "Keyword2"和 "Keyword2"的新 AD 组时配置警报

arrays - 如何从PowerShell中的数组中删除项目?

python - 自动运行脚本时出现 Powershell 错误

powershell - DSC 配置不断重启

c++ - 将 Powershell SecureString 传递给 C++ 程序?

windows - 动力外壳 $?在做直到循环