【问题标题】:PS Pipeline Multiple Parameters BindingPS管道多参数绑定
【发布时间】:2019-05-15 18:22:20
【问题描述】:

我试图通过管道将两个参数传递给一个函数,但它似乎没有按预期工作,我很难理解为什么。

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

输出

名称:值

价值:价值

我尝试运行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

【问题讨论】:

  • 我的理解是每个参数集只有一个参数可以“通过管道”。 ///// 另外,管道一次只能通过管道发送一个项目...所以您的函数一次只能获取一个项目,处理它,将其发送出去,然后获取下一个项目。 ///// 您需要发送一个对象,该对象至少有一个属性绑定到完全您的参数之一。然后另一个可以分配给剩余的参数。

标签: powershell parameters pipeline parameterbinding


【解决方案1】:

根据 Lee Dailey 的评论,您只能让一个参数通过“值”接受来自管道的输入(对于每种值类型,例如 string、int 等)。您的代码当前正在做的是发送一个字符串值数组,然后通过管道一次处理一个。

如果您想将多个值一起发送到管道,您可以通过使这些值成为自定义对象的属性来实现,然后您可以使用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

如果没有这个,只会处理对象集合中的最后一个值。

【讨论】:

  • 干得好;狡辩:ValueFromPipepline 中的单词 valuevalue types 无关;它只是指将输入对象作为一个整体进行绑定,而不管它是值类型的实例还是引用类型。
  • 虽然您的解决方案确实回答了这个问题,但它需要事先创建一个自定义对象。由于内容被定义为“键”或“名称”和“值”,是否有可能以某种方式使用哈希表?我目前正在使用中间函数将哈希表格式化为不理想的自定义对象数组。
  • 您可以通过 splatting 将单个哈希表发送到 cmdlet 中的相同命名参数。它不使用管道,但我认为它可能是您正在寻找的。​​span>
【解决方案2】:

除了@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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    • 2018-03-06
    • 2016-03-06
    • 2016-07-25
    • 1970-01-01
    相关资源
    最近更新 更多