要清楚,我不是说我的命令需要接受多个参数集,它需要调用具有多个参数集的函数。
我的剧本
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, ParameterSetName='NamedCreds')]
[PSCredential] $Credential,
[Parameter(Mandatory=$true, ParameterSetName='NamedCreds')]
[Parameter(Mandatory=$true, ParameterSetName='DefaultCreds')]
[string] $Url,
[Parameter(Mandatory=$true, ParameterSetName='NamedCreds')]
[Parameter(Mandatory=$true, ParameterSetName='DefaultCreds')]
[string] $Path,
[Parameter(Mandatory=$true, ParameterSetName='DefaultCreds')]
[switch] $UseDefaultCredentials
)
#repeating this if block gets tedious
if ($PSCmdlet.ParameterSetName -ieq "NamedCreds")
{
$result = Invoke-RestMethod -Uri $Url -OutFile $Path -Credential $Credential
}
else
{
$result = Invoke-RestMethod -Uri $Url -OutFile $Path -UseDefaultCredentials
}
#do something with result
我想避免使用" if参数集名称,否则"可能最终乱丢脚本的条件。我已经阅读过关于" splatting"但它的例子解释了它是一种避免向右滚动到长参数列表的方法,并且不包括参数集或可选参数。有没有办法调用其他命令并正确处理可选的参数和参数集?
答案 0 :(得分:3)
Splatting是(有点)答案。
您需要条件来确定要传递的参数。您可以使用它们构建哈希表,然后传递一次。
对于您要执行的操作,将-Url
参数重命名为-Uri
,将$Path
重命名为$OutFile
可能更有意义(您可以随时添加如果您更喜欢其他名称,请使用别名),然后直接splat $PSBoundParameters
:
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, ParameterSetName='NamedCreds')]
[PSCredential] $Credential,
[Parameter(Mandatory=$true, ParameterSetName='NamedCreds')]
[Parameter(Mandatory=$true, ParameterSetName='DefaultCreds')]
[Alias('Url')]
[string] $Uri,
[Parameter(Mandatory=$true, ParameterSetName='NamedCreds')]
[Parameter(Mandatory=$true, ParameterSetName='DefaultCreds')]
[Alias('Path')]
[string] $OutFile,
[Parameter(Mandatory=$true, ParameterSetName='DefaultCreds')]
[switch] $UseDefaultCredentials
)
$result = Invoke-RestMethod @PSBoundParameters
}
在此处发表您的评论:
这是一个缩写示例,通常有更多参数 比那个,以及脚本派生的变量 执行该传递给被调用的命令。就是它 要改变这个例子吗?
是的,不幸的是,直接使用$PSBoundParameters
就好了,直到它没有,这通常比你想象的更快(可选参数,某些自动参数等问题)。
它的真正含义是:当你有条件时,你可能无法避免条件限制。
当它开始变得如此复杂时,忽略参数集,只测试除必需参数或具有默认值的所有参数(在所有集合中)。
我只是注意到你正在为某些人命名;你不需要这样做。如果[Parameter()]
属性的内容在每个集合中相同,那么您可以使用单个[Parameter()]
属性而不设置名称;我将在下面更改您的示例以反映这一点。
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, ParameterSetName='NamedCreds')]
[PSCredential] $Credential,
[Parameter(Mandatory=$true)]
[Alias('Url')]
[string] $Uri,
[Parameter(Mandatory=$true)]
[string] $Path,
[Parameter(Mandatory=$true, ParameterSetName='DefaultCreds')]
[switch] $UseDefaultCredentials
)
$params = @{
Uri = $Uri
Path = $Path
}
if ($Credential) {
$params.Credential = $Credential
}
if ($PSBoundParameters.ContainsKey('UseDefaultCredentials')) {
$params.UseDefaultCredentials = $UseDefaultCredentials
}
$result = Invoke-RestMethod @params
}
这是我通常使用的模式。构建一个哈希表,然后将其展开一次。
有一些细微之处需要注意,所以我会进一步细分。
$params = @{
Uri = $Uri
OutFile = $Path
}
在这里创建[hashtable]
。同时,您可以填充始终存在的任何成员。 Uri
和Path
是每个参数集中的强制参数,所以基本上代码不能到达,除非它们具有值(或者更准确;在任何条件下,它们都不能从参数中省略你转到Invoke-RestMethod
)。
如果您没有这些参数,请将其设为空$params = @{}
。
请注意,对于$Path
,我们使密钥OutFile
与将在其中调用的cmdlet中的名称相匹配(因此您可以通过这种方式拥有自己的参数名称。)
if ($Credential) {
$params.Credential = $Credential
}
很容易;测试真实性的参数。如果有什么,请将其添加到$params
。
if ($PSBoundParameters.ContainsKey('UseDefaultCredentials')) {
$params.UseDefaultCredentials = $UseDefaultCredentials
}
这是特殊情况之一。如果我们使用基本的条件检查:
if ($UseDefaultCredentials) {
$params.UseDefaultCredentials = $UseDefaultCredentials
}
然后我们遇到了一个小问题,因为您可以使用如下显式值调用switch参数:Invoke-RestMethod -UseDefaultCredentials:$false
。如果使用简单条件,则不会通过它,但通过检查它是否已绑定,您将检查参数是否已指定,无论其值是什么。
你并不总是必须知道;你可能不想支持使用false显式调用switch参数,在这种情况下继续进行简单的检查。
另请注意,当您指定参数Mandatory
时,您也隐式不允许某些假值。 Mandatory
[String]
不允许空字符串或$null
。数组参数不允许空数组。您必须使用其他属性(例如[AllowEmptyString()]
)明确启用它们。如果你这样做,简单的检查不适用于那些,因为那时你没有通过真正的价值;这是检查$PSBoundParameters
有用的另一个例子。
你可以使用switch参数做的另一件事就是总是把它转换为[bool]
并将它放在哈希表中:
$params.UseDefaultCredentials = $UseDefaultCredentials -as [bool]
# or, during initialization
$params = @{
Uri = $Uri
UseDefaultCredentials = $UseDefaultCredentials -as [bool]
}
这只能通过不属于参数集的开关来完成,因为否则您将把它提供给被调用的命令,即使它不在您的函数上,并且可能导致无效的参数集选择的。
你可以做的其他事情:
使用switch ($PSCmdlet.ParameterSetName)
代替大量if
s,如果在集合上交替更重要(例如,如果您的某些计算值比任何一个特定参数更依赖于集合)。
从绑定参数开始并修改它们:
$params = $PSBoundParameters.Clone()
$params.OutFile = $params.Path
$params.Remove('Path')
$params.NewValue = Invoke-MyAlgorithm
显然没有一个通用的解决方案;无论采取哪种方法取决于您正在做什么以及要求是什么。
一个共同点是:构建一个params哈希表,然后将其展开一次 *
*例外情况适用:-p