我编写了一个函数,它使用四个参数和四个参数集。第一个参数$Path
未分配给一个集合,因此属于所有集合。它也是强制性的,也是唯一可以从管道传递的参数。然而,当我在调用管道末端的函数时,使用其他三个参数的某些组合(所有这些参数都属于四个集合的某个组合(来执行此操作时,我会得到一个错误,指示该集合不明确。
这是我的功能:
function Foo-Bar {
[CmdletBinding(DefaultParameterSetName = 'A')]
param (
[Parameter(Mandatory = $true,
ValueFromPipeline = $true)]
[ValidateNotNullOrEmpty()]
[string[]] $Path,
[Parameter(ParameterSetName = 'A')]
[Parameter(ParameterSetName = 'A-Secure')]
[Switch] $OutputToConsole,
[Parameter(Mandatory = $true,
ParameterSetName = 'B')]
[Parameter(Mandatory = $true,
ParameterSetName = 'B-Secure')]
[int] $OutputMode,
[Parameter(Mandatory = $true,
ParameterSetName = 'A-Secure')]
[Parameter(Mandatory = $true,
ParameterSetName = 'B-Secure')]
[Switch] $Login
)
$PSCmdlet.ParameterSetName
}
所有可能的参数组合如下:
PS C:> Foo-Bar -Path "C:Test.jpg"
A
PS C:> Foo-Bar -Path "C:Test.jpg" -OutputToConsole
A
PS C:> Foo-Bar -Path "C:Test.jpg" -OutputToConsole -Login
A-Secure
PS C:> Foo-Bar -Path "C:Test.jpg" -Login
A-Secure
PS C:> Foo-Bar -Path "C:Test.jpg" -OutputMode 1
B
PS C:> Foo-Bar -Path "C:Test.jpg" -OutputMode 1 -Login
B-Secure
单独通过管道传递$Path,或者与这些其他参数组合使用效果良好:
PS C:> "C:Test.jpg" | Foo-Bar
A
PS C:> "C:Test.jpg" | Foo-Bar -OutputToConsole
A
PS C:> "C:Test.jpg" | Foo-Bar -OutputToConsole -Login
A-Secure
PS C:> "C:Test.jpg" | Foo-Bar -OutputMode 1 -Login
B-Secure
但这两种组合会导致一个错误:
PS C:> "C:Test.jpg" | Foo-Bar -Login
Foo-Bar: Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided.
PS C:> "C:Test.jpg" | Foo-Bar -OutputMode 1
Foo-Bar: Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided.
这些结果之间最大的区别似乎是$OutputToConsole
,这是唯一一个在两个集合中都是可选的参数。似乎通过管道传递一个强制参数会使其本身成为强制参数。另一方面,最令人困惑的结果涉及$OutputMode
,因为它的两个集合都使用了完全强制性参数的不同组合。集合B发生在同时使用$Path
和$OutputMode
的情况下,仅此而已。那么"C:Test.jpg" | Foo-Bar -OutputMode 1
怎么会被认为是不明确的呢?
我将非常感谢任何能为我阐明这一点的人。
不要问我为什么
(下面的解决方法返回与Foo-Bar -?
相同的语法(
就我个人而言,我发现参数集非常混乱和冗长(因此我为层次参数脚本#13746
执行此操作(
无论如何,作为一种可能的变通方法;将Path
参数放入所有参数集中:
function Foo-Bar {
[CmdletBinding(DefaultParameterSetName = 'A')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'A')]
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'B')]
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'A-Secure')]
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'B-Secure')]
[ValidateNotNullOrEmpty()]
[string[]] $Path,
[Parameter(ParameterSetName = 'A')]
[Parameter(ParameterSetName = 'A-Secure')]
[Switch] $OutputToConsole,
[Parameter(Mandatory = $true, ParameterSetName = 'B')]
[Parameter(Mandatory = $true, ParameterSetName = 'B-Secure')]
[int] $OutputMode,
[Parameter(Mandatory = $true, ParameterSetName = 'A-Secure')]
[Parameter(Mandatory = $true, ParameterSetName = 'B-Secure')]
[Switch] $Login
)
$PSCmdlet.ParameterSetName
}
"C:Test.jpg" | Foo-Bar -Login
A-Secure
参数集必须至少包含一个唯一参数
声明参数集若要创建参数集,必须指定每个的Parameter属性的ParameterSetName关键字参数集中的参数。对于属于多个参数集,为每个参数集添加一个"参数"属性。
使用"参数"属性可以定义参数对于每个参数集不同。例如,您可以定义参数在一个集合中是强制性的,在另一个集合则是可选的然而,每个参数集必须至少包含一个唯一的参数
没有指定参数集名称的参数属于所有参数集。
来源:声明参数设置
更新-仔细查看
Foo Bar
ParameterSetName Parameters
---------------- ----------
A -Path <string[]> [-OutputToConsole] [<CommonParameters>]
A-Secure -Path <string[]> -Login [-OutputToConsole] [<CommonParameters>]
B-Secure -Path <string[]> -OutputMode <int> -Login [<CommonParameters>]
B -Path <string[]> -OutputMode <int> [<CommonParameters>]
当您进入时
C:Test.jpg" | Foo-Bar -Login
PoSH无法确定它应该使用A-Secure还是B-Secure。在B安全中,您有一个额外的强制参数(-OutputMode
(并不重要。根据它收到的信息,它无法判断该选择哪一个,因为有多种匹配的选择。这种组合并非独一无二。
"C:Test.jpg" | Foo-Bar -OutputMode 1
这里也一样,只有OutputMode。它收到了一个Path和一个OutputMode参数,但这与B-Secure和B.都匹配。不是唯一的。
Microsoft测量线示例
ParameterSetName Parameters
---------------- ----------
Path [-Path] <string[]> [-Lines] [-Words] [-Characters] [-Recurse] [<CommonParameters>]
PathAll [-Path] <string[]> -All [-Recurse] [<CommonParameters>]
LiteralPath -LiteralPath <string> [-Lines] [-Words] [-Characters] [<CommonParameters>]
LiteralPathAll -LiteralPath <string> -All [<CommonParameters>]
乍一看,Measure Lines示例似乎相似,但不同之处在于前两个参数集采用Path参数,而后两个参数集中采用LiteralPath参数。这使得它们足够独特,Powershell可以知道在使用-All
开关时要使用什么参数集。当与-Path
参数一起使用时,它与PathAll集合一起使用,当提供-LiteralPath
时使用LiteralPathAll。
根据iRons的回答,您还可以大幅减少这里的参数集数量,我认为:
function Foo-Bar {
[CmdletBinding(DefaultParameterSetName = 'None')]
param (
[ValidateNotNullOrEmpty()]
[string[]] $Path,
[Parameter(ParameterSetName = 'A-Secure')]
[Switch] $OutputToConsole,
[Parameter(Mandatory = $true, ParameterSetName = 'B-Secure')]
[int] $OutputMode,
[Parameter(Mandatory = $true, ParameterSetName = 'A-Secure')]
[Parameter(Mandatory = $true, ParameterSetName = 'B-Secure')]
[Switch] $Login
)
$PSCmdlet.ParameterSetName
}
Foo-Bar -Login # --> chosen param set: 'A-Secure' because that the first one mentioned on the Login parameter
Foo-Bar -Path 'D:Testblah.txt' # --> chosen param set: 'None' because that is the DefaultParameterSetName
Foo-Bar -Path 'D:Testblah.txt' -OutputMode 5 # --> prompts you to also supply parameter 'Login'
Foo-Bar -Path 'D:Testblah.txt' -OutputToConsole -Login # --> parameter -OutputMode now not available; chosen param set: 'B-Secure'
Foo-Bar -Path 'D:Testblah.txt' -OutputMode 5 -Login # --> parameter -OutputToConsole now not available; chosen param set: 'A-Secure'
# parameters '-Path' and '-Login' are always available for both 'A-Secure' and 'B-Secure'