【发布时间】:2018-02-21 07:59:27
【问题描述】:
Powershell 的默认行为似乎是将 -WhatIf 和 -Confirm 传播到从使用 -WhatIf 或 -Confirm 调用的函数中调用的所有函数。
但是如果(双关语)我不想要那个怎么办?如果我只想保护在我的系统上执行实际更改的代码而不是我的其余代码怎么办?
这是一个例子:
function Set-Something {
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
[OutputType([string])]
Param (
[Parameter(Mandatory = $false, ValueFromPipeline = $true)]
[string] $ComputerName = $env:COMPUTERNAME
)
Process {
New-Item -Path "beforeChange" -Type File | Out-Null
Remove-Item -Path "beforeChange" -ErrorAction SilentlyContinue
# Here is the bit of code that needs to be "protected"
if ($PSCmdlet.ShouldProcess($ComputerName, "Do something")) {
# Actually do something on $ComputerName
New-Item -Path "inChange" -Type File | Out-Null
Remove-Item -Path "inChange" -ErrorAction SilentlyContinue
}
New-Item -Path "afterChange" -Type File | Out-Null
Remove-Item -Path "afterChange" -ErrorAction SilentlyContinue
}
}
"-"*50 + "Set-Something -WhatIf" + "-"*50
Set-Something -WhatIf
"-"*50 + "Set-Something -Confirm" + "-"*50
Set-Something -Confirm
Set-Something 函数仅在受保护位中执行系统更改内容。它也使用临时文件,但 New-Item 和 Remove-Item 不应触发 WhatIf 或 Confirm。不幸的是,它不是这样工作的:
--------------------------------------------------Set-Something -WhatIf--------------------------------------------------
What if: Performing the operation "Create File" on target "Destination: C:\Users\GO7\beforeChange".
What if: Performing the operation "Do something" on target "GEOCED".
What if: Performing the operation "Create File" on target "Destination: C:\Users\GO7\afterChange".
我可以将-WhatIf:$false -Confirm:$false 添加到每个支持 ShouldProcess 的函数中,但这会很乏味。
所以到目前为止我所做的是:
- 将 $WhatIfPreference 和 $ConfirmPreference 保存在我的函数顶部
- 将这些首选项重置为默认值
- 在受保护的块之前恢复保存的首选项
- 在块内和块外再次重置首选项
像这样:
function Set-Something2 {
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
[OutputType([string])]
Param (
[Parameter(Mandatory = $false, ValueFromPipeline = $true)]
[string] $ComputerName = $env:COMPUTERNAME
)
Begin {
# Save the ShouldProcess parameters for later use
$WhatIfPref = $WhatIfPreference
$ConfirmPref = $ConfirmPreference
# Reset ShouldProcess parameters to their default value
$WhatIfPreference = 0
$ConfirmPreference = 'High'
}
Process {
New-Item -Path "beforeChange" -Type File | Out-Null
Remove-Item -Path "beforeChange" -ErrorAction SilentlyContinue
# We restore the previously saved ShouldProcess parameters just before the "protected" bit of code
$WhatIfPreference = $WhatIfPref
$ConfirmPreference = $ConfirmPref
# Here is the bit of code that needs to be "protected"
if ($PSCmdlet.ShouldProcess($ComputerName, "Do something")) {
# Inside the protected bit, we reset ShouldProcess parameters to their default value
$WhatIfPreference = 0
$ConfirmPreference = 'High'
# Actually do something on $ComputerName
New-Item -Path "inChange" -Type File | Out-Null
Remove-Item -Path "inChange" -ErrorAction SilentlyContinue
}
# After the protected bit, we reset ShouldProcess parameters to their default value
$WhatIfPreference = 0
$ConfirmPreference = 'High'
New-Item -Path "afterChange" -Type File | Out-Null
Remove-Item -Path "afterChange" -ErrorAction SilentlyContinue
}
}
"-"*50 + "Set-Something2 -WhatIf" + "-"*50
Set-Something2 -WhatIf
"-"*50 + "Set-Something2 -Confirm" + "-"*50
Set-Something2 -Confirm
结果如我所愿:
--------------------------------------------------Set-Something2 -WhatIf--------------------------------------------------
What if: Performing the operation "Do something" on target "GEOCED".
--------------------------------------------------Set-Something2 -Confirm--------------------------------------------------
Confirm
Are you sure you want to perform this action?
Performing the operation "Do something" on target "GEOCED".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
但是我应该这样做吗?我觉得它不是很优雅...
【问题讨论】:
-
$ConfirmPreference和$WhatIfPreference是变量,因此它们遵循变量范围规则。 (如果这就是你要问的?) -
我看不到变量作用域在这里有什么帮助?即使我将范围更改为本地,new-item 和 remove-item 仍会触发确认提示,并且如果将 whatif 传递给函数,则不会创建/删除文件。
-
这不是什么“帮助”的问题。这是一个了解它是如何工作的问题。您观察到的行为是设计使然。
-
是的,我了解,Powershell 设计为将这两个首选项从调用者函数传播到所有被调用者。但我不关心 New-Item 要求我确认,我只关心我的函数中的特定代码块。所以我猜我在 Set-Something2 中的做法是绕过这个自动传播功能的正确方法?
-
是的,但正如我所说,为每个支持 ShouldProcess 的函数添加 -WhatIf:$false -Confirm:$false 对于调用大量内置 Powershell 函数或自定义函数的复杂函数来说真的很乏味在同一个文件或其他模块中的函数。
标签: powershell