考虑以下人为的例子:
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"
}
}
}
Run Code Online (Sandbox Code Playgroud)
...及其潜在输出之一:
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
Run Code Online (Sandbox Code Playgroud)
在ShouldContinue循环(第三个for循环)的情况下,我可以看到带有两个 by-reference 布尔参数的重载负责将最终用户是选择Yes to All还是No to All 存储到这两个布尔值中。
但是,在两个ShouldProcess块(前两个for循环)的情况下,这种状态是如何保持的?
特别是,在前两个ShouldProcess块之间,我如何检查是否指定了Yes to All或No to All和/或我需要重置或清除什么才能使第二个ShouldProcess块再次要求确认?
(偏袒ShouldContinue过ShouldProcess是选择细粒度控制,但它似乎失去了本地/内置支持[CmdletBinding(SupportsShouldProcess=$true)]
首先,我将解决$PSCmdlet.ShouldContinue. 无论确认偏好如何,这基本上是一种自行提示的方法。
$PSCmdlet.ShouldProcess另一方面,并不总是提示。它考虑了ConfirmImpact(您设置为High)和$ConfirmPreference默认为的自动变量High。有效值为None、Low、Medium、 和High用于指示更改有多大影响,因此当$ConfirmPreference的值等于或小于命令的ConfirmImpact值时,ShouldProcess将提示。
我知道这不是您的直接问题,但背景对于回答您应该做什么很重要。
直接问题:“答案存储在哪里?” 有一个无聊的答案:它存储在定义ShouldProcess方法的类的内部变量中。
所以,不,不幸的是,你不能自己解决。
但这让我们回到了.ShouldContinue,它可以为您获取这些引用并存储这些值,因此当您需要这些值并希望能够使用它们做出决定时,您应该使用.ShouldContinue.
但是,你真的应该同时使用两者。因为他们做不同的事情。
.ShouldProcess不仅负责确认提示,还负责处理-WhatIf/ $WhatIfPreference;当你说你的命令时,SupportsShouldProcess你也说它支持-WhatIf. 如果您不使用.ShouldProcess,您将遇到以下情况:命令看似安全,但实际上还是要采取行动。
因此,类似这样的模式将涵盖您的基础:
if ($PSCmdet.ShouldProcess('thing', 'do')) {
if ($PSCmdlet.ShouldContinue('prompt')) {
# do it
}
}
Run Code Online (Sandbox Code Playgroud)
这个问题可以追溯到您确认的影响和偏好。如果这些对齐,或者如果用户使用 调用您的命令-Confirm,您将提示两次:一次在 中.ShouldProcess,然后在.ShouldContinue.
不幸的是,这种事情很糟糕。
我写了一个似乎可以解决这个问题的东西。它首先基于一个函数,该函数允许您在确认的情况下运行任意脚本块,以便您.ShouldProcess在抑制其提示的同时仍然可以运行。
然后它还会尝试计算是否需要提示,然后有选择地调用.ShouldContinue. 我没有演示存储或重置 yesToAll 和 noToAll 变量,因为您已经知道如何做到这一点。
这主要是为了演示一种模式,该模式可用于遵守标准确认提示语义,具有可发现性,支持-Confirm参数$ConfirmPreference, and ConfirmImpact,同时保持对-Verboseand 的支持-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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
调用:
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
Run Code Online (Sandbox Code Playgroud)
依此类推,$ConfirmPreference命令的ConfirmImpact.
令人讨厌的一件事是我标记为硬编码的值:它必须与您为该命令设置的确认影响相匹配。
事实证明,以编程方式获得该值有点麻烦,但也许您可以以某种方式解决这个问题。
| 归档时间: |
|
| 查看次数: |
817 次 |
| 最近记录: |