gpt4 book ai didi

powershell - 如果省略了必需的 *pipeline* 参数,是否可以强制 PowerShell 脚本抛出异常?

转载 作者:行者123 更新时间:2023-12-03 09:42:28 29 4
gpt4 key购买 nike

交互式 PowerShell session 会在省略必需参数时提示用户。 Shay Levy offers a workaround到这个问题。问题是当您使用管道绑定(bind)参数时,解决方法不起作用。

考虑这个例子:

function f {
[CmdletBinding()]
param
(
[Parameter(ValueFromPipeLineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$a=$(throw "a is mandatory, please provide a value.")
)
process{}
}

$o = New-Object psobject -Property @{a=1}
$o | f

尽管 $o.a 是绑定(bind)到 f -a 的完美值,但它会引发异常。出于某种原因,PowerShell 会评估参数 $a 的默认值,即使 $a 的值注定要从管道绑定(bind)。

在交互式运行时缺少必需参数时,是否有其他方法可以强制 PowerShell 抛出异常?


为什么这很重要?它浪费了程序员的时间。方法如下:

  • 堆栈跟踪深度为 20 次调用是很正常的。当调用堆栈深处的调用由于未收到强制参数而阻塞时,调试起来效率非常低。没有堆栈跟踪,没有错误消息,也没有上下文。您所看到的只是参数值的提示。祝你好运,猜到为什么会这样。您始终可以通过调试找到解决方案,只是花费的时间比应有的多,因为您没有获得通常从抛出的异常中获得的信息。

  • 假设您正在运行一系列配置测试用例,并且 1000 个中有 一个 有这个问题。平均而言,这些测试用例中有 500 个没有运行。因此,在此测试运行中,您只能获得一半案例的测试结果。如果这些测试运行通宵运行,您可能需要再等 24 小时才能获得结果。所以现在你的迭代速度变慢了。

最佳答案

这不起作用的原因是管道参数具有不同的值,具体取决于您是在 Begin{}Process{} 还是 End {} block 。在某些时候,默认值会被评估,因此会抛出异常。这是我不喜欢那个特别技巧的原因之一。

一个合适的解决方案(我希望)

I liked it so much I wrote a blog post about it所以我希望你觉得它有用。

function Validate-MandatoryOptionalParameters {
[CmdletBinding()]
param(
[Parameter(
Mandatory=$true
)]
[System.Management.Automation.CommandInfo]
$Context ,

[Parameter(
Mandatory=$true,
ValueFromPipeline=$true
)]
[System.Collections.Generic.Dictionary[System.String,System.Object]]
$BoundParams ,

[Switch]
$SetBreakpoint
)

Process {
foreach($param in $Context.Parameters.GetEnumerator()) {
if ($param.Value.Aliases.Where({$_ -imatch '^Required_'})) {
if (!$BoundParams[$param.Key]) {
if ($SetBreakpoint) {
$stack = Get-PSCallStack | Select-Object -Index 1
Set-PSBreakpoint -Line $stack.ScriptLineNumber -Script $stack.ScriptName | Write-Debug
} else {
throw [System.ArgumentException]"'$($param.Key)' in command '$($Context.Name)' must be supplied by the caller."
}
}
}
}
}
}

我认为这样做的最大优势在于无论您有多少参数或它们的名称是什么,它都会以相同的方式被调用。

关键是你只需要为每个以Required_开头的参数添加一个别名。

示例:

function f {
[CmdletBinding()]
param(
[Parameter(
ValueFromPipeline=$true
)]
[Alias('Required_Param1')]
$Param1
)

Process {
$PSBoundParameters | Validate-MandatoryOptionalParameters -Context $MyInvocation.MyCommand
}
}

根据我们的聊天对话和您的用例,我设置了一个断点而不是抛出异常。似乎它可能有用,但不确定。帖子中有更多信息。

也可用作 GitHub Gist (包括基于评论的帮助)。


我认为您要解决此问题的唯一方法是检查流程 block 中的值。

Process {
if (!$a) {
throw [System.ArgumentException]'You must supply a value for the -a parameter.'
}
}

如果您控制脚本的调用,您可以使用 powershell.exe -NonInteractive 并且应该抛出(或至少退出)而不是提示。

验证函数示例

function Validate-Parameter {
[CmdletBinding()]
param(
[Parameter(
Mandatory=$true , #irony
ValueFromPipeline=$true
)]
[object]
$o ,

[String]
$Message
)

Begin {
if (!$Message) {
$Message = 'The specified parameter is required.'
}
}

Process {
if (!$o) {
throw [System.ArgumentException]$Message
}
}
}

# Usage

Process {
$a | Validate-Parameter -Message "-a is a required parameter"
$a,$b,$c,$d | Validate-Parameter
}

关于powershell - 如果省略了必需的 *pipeline* 参数,是否可以强制 PowerShell 脚本抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33600279/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com