我在我编写的自定义函数中看到了一些奇怪的行为,因此我编写了一些具有不同特征的快速测试函数来展示这些行为。当参数集足够相似时,问题就出现了,唯一的区别因素是通过管道接收的对象的类型。
首先,我创建了一个简单的类型,它只与字符串不同。
Add-Type @"
public class TestType {
public string Prop1;
}
"@
接下来,我创建了一个测试函数,并使用字符串和TestType输入运行它。
function Test-ParameterSets1
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Str")] [string] $StringInput,
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Test")] [TestType] $TestInput
)
begin {
$result = New-Object Object | Select-Object –Property @{n='FunctionName';e={$PSCmdlet.MyInvocation.InvocationName}},@{n='ParameterSetName';e={$PSCmdlet.ParameterSetName}}
}
process {
$result | Add-Member -MemberType NoteProperty -Name StringInput -Value $StringInput -PassThru | Add-Member -MemberType NoteProperty -Name TestInput -Value $TestInput
}
end {
$result
}
}
'string' | Test-ParameterSets1
New-Object TestType | Test-ParameterSets1
FunctionName ParameterSetName StringInput TestInput
------------ ---------------- ----------- ---------
Test-ParameterSets1 __AllParameterSets string
Test-ParameterSets1 __AllParameterSets TestType
这是问题的核心。 ParameterSetName的计算结果为__AllParameterSets
,即使从值中看到,参数也按预期设置。我的函数有很多参数集,并根据参数集进行大量切换来控制逻辑流程。
接下来我尝试添加一个参数集唯一的参数,并且正如预期的那样,ParameterSetName对于仅指定它的调用是正确的。
function Test-ParameterSets2
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Str")] [string] $StringInput,
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Test")] [TestType] $TestInput,
[Parameter(ParameterSetName="Test")] [string] $TestName
)
begin {
$result = New-Object Object | Select-Object –Property @{n='FunctionName';e={$PSCmdlet.MyInvocation.InvocationName}},@{n='ParameterSetName';e={$PSCmdlet.ParameterSetName}}
}
process {
$result | Add-Member -MemberType NoteProperty -Name StringInput -Value $StringInput -PassThru | Add-Member -MemberType NoteProperty -Name TestInput -Value $TestInput
}
end {
$result
}
}
'string' | Test-ParameterSets2
New-Object TestType | Test-ParameterSets2 -TestName MyName
New-Object TestType | Test-ParameterSets2
FunctionName ParameterSetName StringInput TestInput
------------ ---------------- ----------- ---------
Test-ParameterSets2 __AllParameterSets string
Test-ParameterSets2 Test TestType
Test-ParameterSets2 __AllParameterSets TestType
接下来,我尝试添加一个对两个参数集都是必需的参数,这次ParameterSetName计算为空字符串,这特别令人困惑。
function Test-ParameterSets5
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Str")] [string] $StringInput,
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Test")] [TestType] $TestInput,
[Parameter(Mandatory=$true, ParameterSetName="Str")] [Parameter(Mandatory=$true, ParameterSetName="Test")] [string] $Mandatory,
[Parameter(ParameterSetName="Test")] [string] $TestName
)
begin {
$result = New-Object Object | Select-Object –Property @{n='FunctionName';e={$PSCmdlet.MyInvocation.InvocationName}},@{n='ParameterSetName';e={$PSCmdlet.ParameterSetName}}
}
process {
$result | Add-Member -MemberType NoteProperty -Name StringInput -Value $StringInput -PassThru | Add-Member -MemberType NoteProperty -Name TestInput -Value $TestInput
}
end {
$result
}
}
'string' | Test-ParameterSets5 -Mandatory mandatoryParam
New-Object TestType | Test-ParameterSets5 -Mandatory mandatoryParam -TestName MyName
New-Object TestType | Test-ParameterSets5 -Mandatory mandatoryParam
FunctionName ParameterSetName StringInput TestInput
------------ ---------------- ----------- ---------
Test-ParameterSets5 string
Test-ParameterSets5 Test TestType
Test-ParameterSets5 TestType
似乎PowerShell确实知道如何正确设置这些参数,但是ParameterSetName没有正确评估。有没有办法让这个工作?我希望避免使用不必要的开关,例如-String和-TestType,这些开关对于它们自己的参数集是唯一的,这样PowerShell才能完成它的工作。谢谢!
答案 0 :(得分:3)
您的代码的问题在于您阅读了ParameterSetName
块中的begin
属性。当命令接受管道输入时,输入对象可以影响所选的ParameterSetName
。如果你的命令有多个输入对象,那么它们中的每一个都会导致选择不同的参数集:
class a { }
class b { }
class c { }
function f {
param(
[Parameter(ParameterSetName='a', ValueFromPipeline)][a]$a,
[Parameter(ParameterSetName='b', ValueFromPipeline)][b]$b,
[Parameter(ParameterSetName='c', ValueFromPipeline)][c]$c
)
begin {
"ParameterSetName in begin block: $($PSCmdlet.ParameterSetName)"
}
process {
"ParameterSetName in process block: $($PSCmdlet.ParameterSetName)"
}
}
[a]::new(), [b]::new(), [c]::new() | f
# Result:
# ParameterSetName in begin block: __AllParameterSets
# ParameterSetName in process block: a
# ParameterSetName in process block: b
# ParameterSetName in process block: c
因此,如果您想知道输入对象绑定到命令后选择了哪个参数集,那么您应该阅读ParameterSetName
块中的process
。
答案 1 :(得分:0)
要完成基于@ PerSetAI建议的示例,这里是测试过程块中的parameterset的相同示例函数。
import {SpreadsheetApp} from '@types/google-apps-script';