如果省略必需的* pipeline *参数,是否可以强制PowerShell脚本抛出? [英] Is it possible to force PowerShell script to throw if a required *pipeline* parameter is omitted?

查看:108
本文介绍了如果省略必需的* pipeline *参数,是否可以强制PowerShell脚本抛出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当省略必需的参数时,交互式PowerShell会话会提示用户. Shay Levy提供了针对此问题的解决方法.问题是,当您使用管道绑定参数时,解决方法不起作用.

Interactive PowerShell sessions prompt the user when a required parameter is omitted. Shay Levy offers a workaround to this problem. The problem is that workaround does not work when you use the pipeline to bind parameters.

请考虑以下示例:

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是绑定到f -a的一个很好的值,但是这将引发异常.由于某些原因,PowerShell会评估参数$a的默认值,即使$a的值注定要与管道绑定.

This throws an exception despite that $o.a is a perfectly good value to bind to f -a. For some reason PowerShell evaluates the default value for parameter $a even if there is a value for $a that is destined to be bound from the pipeline.

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

Is there some other way to force PowerShell to throw an exception when a mandatory parameter is missing when running interactively?

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

Why does this matter? It wastes programmer time. Here's how:

  • 堆栈跟踪深度为20个调用是很正常的.如果由于未接收到强制性参数而导致调用堆栈中的某个调用阻塞,则调试效率将大大降低.没有堆栈跟踪,没有错误消息,也没有上下文.您所看到的只是提示输入参数值.祝你好运,确切地猜测为什么会这样.您总是可以调试解决方案的方法,它花费的时间比应该花费的时间要多,因为您没有从抛出的异常中获取正常的信息.

  • It's pretty normal for the stack trace to be 20 calls deep. When a call deep in the call stack blocks because it didn't receive a mandatory parameter things become very inefficient to debug. There is no stack trace, no error messages, and no context. All you see is a prompt for the parameter value. Good luck guessing exactly why that occurred. You can always debug your way to a solution, it just takes way more time than it should because you're not getting the information you normally would from a thrown exception.

假设您正在运行一系列配置测试用例,而 one 中的1000个有此问题.平均而言,这些测试用例中有500个没有运行.因此,在此测试运行中,您只能从一半的案例中获得测试结果.如果这些测试运行在一夜之间进行,则可能需要再等待24个小时才能获得结果.所以现在您的迭代速度变慢了.

Suppose you are running a series of configuration test cases and one of 1000 has this problem. On average, 500 of those test cases don't run. So you only get test results from half of your cases on this test run. If those test runs were running overnight, you might have to wait another 24 hours to get the results. So now you're iterating slower.

推荐答案

前言

我看到的所有解决方案都只是解决此基本问题的方法:在非交互模式下,PowerShell在缺少参数时会引发异常.在交互模式下,无法告诉PowerShell以相同的方式引发异常.

Preface

All of the solutions I have seen are mere workarounds to this fundamental problem: In non-interactive mode PowerShell throws an exception when a parameter is missing. In interactive mode, there is no way to tell PowerShell to throw an exception in the same way.

在此问题上,连接上确实应该存在一个问题.我尚未能够在Connect上对此进行适当的搜索.

There really ought to be an issue opened on Connect for this problem. I haven't been able to do a proper search for this on Connect yet.

只要您以任何方式涉及到管道进行参数绑定,丢失的参数都会产生错误.而且,如果$ErrorActionPreference -eq 'Stop'它将引发异常:

As soon as you involve the pipeline for parameter binding in any way, missing parameters produce an error. And, if $ErrorActionPreference -eq 'Stop' it throws an exception:

function f {
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   ValueFromPipeLineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$a,

        [Parameter(Mandatory = $true ,
                   ValueFromPipeLineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$b,

        [Parameter(ValueFromPipeLineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$c
    )
    process{}
}

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

因为参数b是强制性的,所以会抛出ParameterBindingException.请注意,有些奇怪之处与捕获该异常有关PowerShell 2 .

That throws ParameterBindingException for parameter b because it is mandatory. Note that there's some bizarreness related to catching that exception under PowerShell 2.

我通过管道测试了一些不同的变体和splatted参数,并且看起来以任何方式涉及管道绑定都可以避免提示用户.

I tested a few different variations using piped and splatted parameters, and it looks like involving pipeline binding in any way avoids prompting the user.

不幸的是,这意味着每次您调用可能缺少参数的命令时,都会创建一个参数对象.这通常涉及到New-Object psobject -Property @{}的相当冗长的调用.由于我希望经常使用此技术,因此我创建了 (和别名>>)将splat参数转换为参数对象.使用>>会导致代码看起来像这样:

Unfortunately, this means creating a parameters object every time you invoke a command where parameters might be missing. That normally involves a rather verbose call to New-Object psobject -Property @{}. Since I expect to use this technique often, I created ConvertTo-ParamObject (and alias >>) to convert splat parameters to a parameter object. Using >> results in code that looks something like this:

$UnvalidatedParams | >> | f

现在假设$UnvalidatedParams是一个哈希表,该哈希表来自可能省略了f强制性参数之一的某个地方.使用上述方法调用f会导致错误,而不是有问题的用户提示.如果$ErrorActionPreferenceStop,则会引发一个异常,您可以捕获该异常.

Now suppose $UnvalidatedParams is a hashtable that came from somewhere that may have omitted one of f's mandatory parameters. Invoking f using the above method results in an error instead of the problematic user prompt. And if $ErrorActionPreference is Stop, it throws an exception which you can catch.

我已经重构了一些代码来使用这种技术,我很乐观地认为这是我尝试过的最坏的解决方法. @Briantist的技术确实相当聪明,但是如果您无法更改要调用的cmdlet,则将无法正常工作.

I've already refactored a bit of code to use this technique, and I'm optimistic that this is the least-bad workaround I've tried. @Briantist's technique is really rather clever, but it doesn't work if you can't change the cmdlet you are invoking.

这篇关于如果省略必需的* pipeline *参数,是否可以强制PowerShell脚本抛出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆