PowerShell函数参数:第一个可以先选择吗?

时间:2010-05-31 08:18:19

标签: powershell parameters

我在PowerShell中有一个高级功能,大致如下所示:

function Foo {
    [CmdletBinding]
    param (
        [int] $a = 42,
        [int] $b
    )
}

这个想法是它可以用两个,一个或没有参数运行。但是,成为可选的第一个参数是第一个。因此,以下方案可以运行该功能:

Foo a b    # the normal case, both a and b are defined
Foo b      # a is omitted
Foo        # both a and b are omitted

但是,通常PowerShell会尝试将单个参数放入 a 中。所以我考虑明确指定参数位置,其中 a 将位置0和 b 位置1.但是,仅允许指定 b 我尝试将 a 放入参数集。但是 b 需要一个不同的位置,具体取决于当前使用的参数集。

任何想法如何妥善解决?我想保留参数名称(实际上不是 a b ),因此使用$args可能是最后的手段。我可能可以定义两个参数集,一个有两个必需参数,一个有一个可选参数,但我猜参数名称在这种情况下必须不同,那么,对吗?

3 个答案:

答案 0 :(得分:5)

关于如何妥善解决这个问题的想法?不,我argued for a similar feature如果位置0的参数是管道绑定的,那么任何其他参数的“位置”会向下滑动,这样你就可以继续提供位置参数,而不必诉诸于所有命名参数。该团队认为这对于人们来说太混乱了 - 有参数转移位置。此行为是将管道绑定参数放在位置参数末尾的一个很好的理由。 : - )

带有高级功能的BTW,$ args不是一个选项。有点像$ _ - 它不适用。请使用ValueFromRemainingArguments代替,例如:

    [Parameter(ValueFromRemainingArguments=$true)]
    $rest

答案 1 :(得分:2)

我担心你无法做到这一点。你可以得到的最接近的是必须命名第一个参数。可选的未命名位置参数必须是集合中的最后一个。

function test-optional {
    [cmdletbinding(defaultparametersetname="SingleOrNone")]
    param(
        [parameter(
            parametersetname="Both",
            mandatory=$true,
            position=1)]      
        [int]$A,

        [parameter(
            parametersetname="Both",
            mandatory=$false,
            position=2)]
        [parameter(
            parametersetname="SingleOrNone",
            mandatory=$false,
            position=1)]
        [int]$B   
    )

    end {
        "parameterset: {0}; a: $a; b: $b" -f $pscmdlet.parametersetname, $a, $b
    }
}

test-optional 1 # ok
test-optional 3 4 # fail
test-optional -a 3 4 # ok
test-optional -a 1 # ok
test-optional -b 1 # ok
test-optional -a 1 -b 2 # ok
test-optional # ok

答案 2 :(得分:0)

您可以使用动态参数(在“about_Functions_Advanced_Parameters”中记录)来执行此操作,这可能是“正确的”解决方案。但是根据你的论点的复杂性,你可以通过几种方式达到同样的效果。

您可以使用正确的参数排列来递归调用函数:

    function ff($a, $b) { 
        if (!$PSBoundParameters.ContainsKey('b')) {
            ff -b $a; return
        }

        # main logic
        "a: $a"
        "b: $b" 
    }

这导致:

PS C:\Users\Droj> ff one two
a: one
b: two
PS C:\Users\Droj> ff one
a:
b: one
PS C:\Users\Droj> ff
a:
b:

但是,这不允许您为参数定义不同的类型或验证。因此,如果您需要,另一个选择是将主逻辑包装在脚本块中,并根据传入的内容传入正确的参数。如下所示:

function ff() {
    param($a, $b)
    $go = {
        param($a, $b)
        "a: $a"
        "b: $b"
    }
    if (!$PSBoundParameters.ContainsKey('b')) { 
        &$go -b $a 
    } 
    else {
        &$go @PSBoundParameters
    }
}

...导致相同的输出。

希望有所帮助!