PS 管道多参数绑定
PS Pipeline Multiple Parameters Binding
我试图通过管道将两个参数传递给一个函数,但它似乎没有按预期工作,我很难理解为什么。
MWE
function Test-Pipeline {
[CmdletBinding ()]
Param(
[Parameter(ValueFromPipeline=$true)][String]$Name,
[Parameter(ValueFromPipeline=$true)][String]$Value
)
Write-Host "Name: $Name"
Write-Host "Value: $Value"
}
"Name", "Value" | Test-Pipeline
输出
Name: Value
Value: Value
我尝试了 运行 Trace-Command
命令来查看发生了什么。在第 35 行我们可以看到 Value
绑定到 $Parameter
.
为什么 PowerShell 将第二个输入绑定到两个参数?如果这是预料之中的,为什么它只发生在第二个参数而不是第一个参数?
追踪
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : BIND arg [] to parameter [Name]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION:
DEBUG: ParameterBinding Information: 0 : COERCE arg to [System.String]
DEBUG: ParameterBinding Information: 0 : Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 : BIND arg [] to param [Name] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND arg [] to parameter [Value]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION:
DEBUG: ParameterBinding Information: 0 : COERCE arg to [System.String]
DEBUG: ParameterBinding Information: 0 : Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 : BIND arg [] to param [Value] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : PIPELINE object TYPE = [System.String]
DEBUG: ParameterBinding Information: 0 : RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 : Parameter [Value] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 : BIND arg [Name] to parameter [Value]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION: Name
DEBUG: ParameterBinding Information: 0 : BIND arg [Name] to param [Value] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : Parameter [Name] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 : BIND arg [Name] to parameter [Name]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION: Name
DEBUG: ParameterBinding Information: 0 : BIND arg [Name] to param [Name] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : PIPELINE object TYPE = [System.String]
DEBUG: ParameterBinding Information: 0 : RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 : Parameter [Name] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 : BIND arg [Value] to parameter [Name]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION: Value
DEBUG: ParameterBinding Information: 0 : BIND arg [Value] to param [Name] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : Parameter [Value] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 : BIND arg [Value] to parameter [Value]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION: Value
DEBUG: ParameterBinding Information: 0 : BIND arg [Value] to param [Value] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Write-Host]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Write-Host]
DEBUG: ParameterBinding Information: 0 : BIND REMAININGARGUMENTS cmd line args to param: [Object]
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Collections.Generic.List`1[System.Object]] to parameter [Object]
DEBUG: ParameterBinding Information: 0 : COERCE arg to [System.Object]
DEBUG: ParameterBinding Information: 0 : Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Collections.Generic.List`1[System.Object]] to param [Object] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Write-Host]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
Name: Value
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Write-Host]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Write-Host]
DEBUG: ParameterBinding Information: 0 : BIND REMAININGARGUMENTS cmd line args to param: [Object]
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Collections.Generic.List`1[System.Object]] to parameter [Object]
DEBUG: ParameterBinding Information: 0 : COERCE arg to [System.Object]
DEBUG: ParameterBinding Information: 0 : Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Collections.Generic.List`1[System.Object]] to param [Object] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Write-Host]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
Value: Value
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
根据 Lee Dailey 的评论,您只能通过 "Value" 让一个参数接受来自管道的输入(对于每种值类型,例如字符串、整数等)。您的代码当前正在做的是发送一组字符串值,然后通过管道一次处理一个。
如果您想将多个值一起发送到管道中,您可以通过使这些值成为自定义对象的属性来实现,然后您可以使用 ValueFromPipelineByPropertyName
通过管道接受它们参数。这通过匹配与输入参数同名的输入对象的任何属性来工作:
function Test-Pipeline {
[CmdletBinding ()]
Param(
[Parameter(ValueFromPipelineByPropertyName=$true)][String]$Name,
[Parameter(ValueFromPipelineByPropertyName=$true)][String]$Value
)
Write-Host "Name: $Name"
Write-Host "Value: $Value"
}
$MyObject = [pscustomobject]@{
Name = "MyName"
Value = "MyValue"
}
$MyObject | Test-Pipeline
结果:
Name: MyName
Value: MyValue
另一种类似的方法是使用 ValueFromPipeline
接受输入对象,然后从该对象获取 属性 值:
function Test-Pipeline {
[CmdletBinding ()]
Param(
[Parameter(ValueFromPipeline=$true)][Object]$InputObject
)
$Name = $InputObject.Name
$Value = $InputObject.Value
Write-Host "Name: $Name"
Write-Host "Value: $Value"
}
$MyObject = [pscustomobject]@{
Name = "MyName"
Value = "MyValue"
}
$MyObject | Test-Pipeline
一些 cmdlet 将支持这两种方法,因为 PowerShell 将首先尝试按对象类型进行匹配,然后恢复为按 属性 名称进行匹配。如果您想了解更多,这里有详细的解释:https://blogs.technet.microsoft.com/heyscriptingguy/2013/03/25/learn-about-using-powershell-value-binding-by-property-name/
请注意,如果您要通过管道成功处理值,您还需要在函数中使用 Process { }
块,这会导致一次处理一个对象集合:
function Test-Pipeline {
[CmdletBinding ()]
Param(
[Parameter(ValueFromPipeline=$true)][Object]$InputObject
)
Process {
$Name = $InputObject.Name
$Value = $InputObject.Value
Write-Host "Name: $Name"
Write-Host "Value: $Value"
}
}
$MyObject = @(
[pscustomobject]@{
Name = "MyName"
Value = "MyValue"
}
[pscustomobject]@{
Name = "MySecondName"
Value = "MySecondValue"
}
)
$MyObject | Test-Pipeline
如果不这样做,只会处理对象集合中的最后一个值。
除了@Mark 的回答,如前所述,ValueFromPipeline 属性只能为每个参数类型设置一次。
这是使用多个 ValueFromPipeline 的示例,每个用于不同的参数类型。
每次迭代只分配一个参数。与输入值类型匹配的那个。
注:
当初始化时没有使用特定值时,$Int 包含 0
。
更安全的是检查使用了哪个参数集,而不仅仅是是否分配了值。
function testus() {
param(
[Parameter(ValueFromPipeline, ParameterSetName = "A")]
[String]$Str,
[Parameter(ValueFromPipeline, ParameterSetName = "B")]
[Int]$Int
)
process {
if ($PSCmdlet.ParameterSetName -eq 'A') {
Write-Host ""
Write-Host "String was used:"
Write-Host "Str: $Str"
Write-Host "(Int contains initialized default value '0': $Int)"
} elseif ($PSCmdlet.ParameterSetName -eq 'B') {
Write-Host ""
Write-Host "Integer was used:"
Write-Host "Int: $Int"
Write-Host "(Str contains initialized default value '' (empty string): $($Str.gettype().FullName))"
}
}
}
'a', 1, 0 | testus
我试图通过管道将两个参数传递给一个函数,但它似乎没有按预期工作,我很难理解为什么。
MWE
function Test-Pipeline {
[CmdletBinding ()]
Param(
[Parameter(ValueFromPipeline=$true)][String]$Name,
[Parameter(ValueFromPipeline=$true)][String]$Value
)
Write-Host "Name: $Name"
Write-Host "Value: $Value"
}
"Name", "Value" | Test-Pipeline
输出
Name: Value
Value: Value
我尝试了 运行 Trace-Command
命令来查看发生了什么。在第 35 行我们可以看到 Value
绑定到 $Parameter
.
为什么 PowerShell 将第二个输入绑定到两个参数?如果这是预料之中的,为什么它只发生在第二个参数而不是第一个参数?
追踪
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : BIND arg [] to parameter [Name]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION:
DEBUG: ParameterBinding Information: 0 : COERCE arg to [System.String]
DEBUG: ParameterBinding Information: 0 : Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 : BIND arg [] to param [Name] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND arg [] to parameter [Value]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION:
DEBUG: ParameterBinding Information: 0 : COERCE arg to [System.String]
DEBUG: ParameterBinding Information: 0 : Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 : BIND arg [] to param [Value] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : PIPELINE object TYPE = [System.String]
DEBUG: ParameterBinding Information: 0 : RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 : Parameter [Value] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 : BIND arg [Name] to parameter [Value]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION: Name
DEBUG: ParameterBinding Information: 0 : BIND arg [Name] to param [Value] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : Parameter [Name] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 : BIND arg [Name] to parameter [Name]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION: Name
DEBUG: ParameterBinding Information: 0 : BIND arg [Name] to param [Name] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : PIPELINE object TYPE = [System.String]
DEBUG: ParameterBinding Information: 0 : RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 : Parameter [Name] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 : BIND arg [Value] to parameter [Name]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION: Value
DEBUG: ParameterBinding Information: 0 : BIND arg [Value] to param [Name] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : Parameter [Value] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 : BIND arg [Value] to parameter [Value]
DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 : result returned from DATA GENERATION: Value
DEBUG: ParameterBinding Information: 0 : BIND arg [Value] to param [Value] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Test-Pipeline]
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Write-Host]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Write-Host]
DEBUG: ParameterBinding Information: 0 : BIND REMAININGARGUMENTS cmd line args to param: [Object]
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Collections.Generic.List`1[System.Object]] to parameter [Object]
DEBUG: ParameterBinding Information: 0 : COERCE arg to [System.Object]
DEBUG: ParameterBinding Information: 0 : Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Collections.Generic.List`1[System.Object]] to param [Object] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Write-Host]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
Name: Value
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Write-Host]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Write-Host]
DEBUG: ParameterBinding Information: 0 : BIND REMAININGARGUMENTS cmd line args to param: [Object]
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Collections.Generic.List`1[System.Object]] to parameter [Object]
DEBUG: ParameterBinding Information: 0 : COERCE arg to [System.Object]
DEBUG: ParameterBinding Information: 0 : Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Collections.Generic.List`1[System.Object]] to param [Object] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Write-Host]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
Value: Value
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
根据 Lee Dailey 的评论,您只能通过 "Value" 让一个参数接受来自管道的输入(对于每种值类型,例如字符串、整数等)。您的代码当前正在做的是发送一组字符串值,然后通过管道一次处理一个。
如果您想将多个值一起发送到管道中,您可以通过使这些值成为自定义对象的属性来实现,然后您可以使用 ValueFromPipelineByPropertyName
通过管道接受它们参数。这通过匹配与输入参数同名的输入对象的任何属性来工作:
function Test-Pipeline {
[CmdletBinding ()]
Param(
[Parameter(ValueFromPipelineByPropertyName=$true)][String]$Name,
[Parameter(ValueFromPipelineByPropertyName=$true)][String]$Value
)
Write-Host "Name: $Name"
Write-Host "Value: $Value"
}
$MyObject = [pscustomobject]@{
Name = "MyName"
Value = "MyValue"
}
$MyObject | Test-Pipeline
结果:
Name: MyName
Value: MyValue
另一种类似的方法是使用 ValueFromPipeline
接受输入对象,然后从该对象获取 属性 值:
function Test-Pipeline {
[CmdletBinding ()]
Param(
[Parameter(ValueFromPipeline=$true)][Object]$InputObject
)
$Name = $InputObject.Name
$Value = $InputObject.Value
Write-Host "Name: $Name"
Write-Host "Value: $Value"
}
$MyObject = [pscustomobject]@{
Name = "MyName"
Value = "MyValue"
}
$MyObject | Test-Pipeline
一些 cmdlet 将支持这两种方法,因为 PowerShell 将首先尝试按对象类型进行匹配,然后恢复为按 属性 名称进行匹配。如果您想了解更多,这里有详细的解释:https://blogs.technet.microsoft.com/heyscriptingguy/2013/03/25/learn-about-using-powershell-value-binding-by-property-name/
请注意,如果您要通过管道成功处理值,您还需要在函数中使用 Process { }
块,这会导致一次处理一个对象集合:
function Test-Pipeline {
[CmdletBinding ()]
Param(
[Parameter(ValueFromPipeline=$true)][Object]$InputObject
)
Process {
$Name = $InputObject.Name
$Value = $InputObject.Value
Write-Host "Name: $Name"
Write-Host "Value: $Value"
}
}
$MyObject = @(
[pscustomobject]@{
Name = "MyName"
Value = "MyValue"
}
[pscustomobject]@{
Name = "MySecondName"
Value = "MySecondValue"
}
)
$MyObject | Test-Pipeline
如果不这样做,只会处理对象集合中的最后一个值。
除了@Mark 的回答,如前所述,ValueFromPipeline 属性只能为每个参数类型设置一次。
这是使用多个 ValueFromPipeline 的示例,每个用于不同的参数类型。
每次迭代只分配一个参数。与输入值类型匹配的那个。
注:
当初始化时没有使用特定值时,$Int 包含 0
。
更安全的是检查使用了哪个参数集,而不仅仅是是否分配了值。
function testus() {
param(
[Parameter(ValueFromPipeline, ParameterSetName = "A")]
[String]$Str,
[Parameter(ValueFromPipeline, ParameterSetName = "B")]
[Int]$Int
)
process {
if ($PSCmdlet.ParameterSetName -eq 'A') {
Write-Host ""
Write-Host "String was used:"
Write-Host "Str: $Str"
Write-Host "(Int contains initialized default value '0': $Int)"
} elseif ($PSCmdlet.ParameterSetName -eq 'B') {
Write-Host ""
Write-Host "Integer was used:"
Write-Host "Int: $Int"
Write-Host "(Str contains initialized default value '' (empty string): $($Str.gettype().FullName))"
}
}
}
'a', 1, 0 | testus