喷溅是(某种程度上)这个问题的答案。
您需要您的条件来确定要传递的参数。您可以使用它们构建哈希表,然后传递一次。
对于您要执行的操作,将-Url 参数重命名为-Uri 并将$Path 重命名为$OutFile 可能更有意义(如果您喜欢其他名称,您可以随时添加别名更好),然后直接喷$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
}
将在此处处理您的评论:
这是一个缩略的例子,通常有更多的参数
除此之外,还有在脚本运行时派生的变量
执行 get 传递给被调用的命令。就是它
要改变这个例子吗?
是的,不幸的是,像这样直接使用$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 是每个参数集中的强制参数,因此基本上代码无法到达此处,除非它们具有值(或更准确地说;在任何情况下,它们都不能从传递给 @ 的参数中省略987654335@)。
如果您没有任何这些参数,则将其设为空 $params = @{}。
请注意,对于 $Path,我们将键 OutFile 与将要调用的 cmdlet 中的名称匹配(因此您可以通过这种方式拥有自己的参数名称)。
if ($Credential) {
$params.Credential = $Credential
}
很简单;测试参数的真实性。如果那里有东西,请将其添加到$params。
if ($PSBoundParameters.ContainsKey('UseDefaultCredentials')) {
$params.UseDefaultCredentials = $UseDefaultCredentials
}
这是其中一种特殊情况。如果我们改用基本条件检查:
if ($UseDefaultCredentials) {
$params.UseDefaultCredentials = $UseDefaultCredentials
}
那么我们有一个小问题,因为您可以使用如下显式值调用开关参数: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) 而不是大量的ifs,如果在集合上交替更重要(例如,如果您的某些计算值比任何一个特定参数更依赖集合)。
从绑定参数入手并修改:
$params = $PSBoundParameters.Clone()
$params.OutFile = $params.Path
$params.Remove('Path')
$params.NewValue = Invoke-MyAlgorithm
显然没有万能的解决方案;无论您采用哪种方法,都取决于您正在做什么以及要求是什么。
一个共同点是:构建一个参数哈希表,然后将其分解一次*
* 例外情况适用:-p