Связывание нескольких параметров конвейера PS - PullRequest
0 голосов
/ 14 декабря 2018

Я пытаюсь передать два параметра функции через конвейер, но она не работает должным образом, и я пытаюсь понять, почему.

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 связывает второй вход с обоими параметрами?Если это ожидается, почему это происходит только для второго параметра, а не для первого?

Trace

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

1 Ответ

0 голосов
/ 14 декабря 2018

Согласно комментарию Ли Дейли, у вас может быть только один параметр, принимающий входные данные из конвейера через «Значение» (для каждого типа значения, например, 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

Некоторые командлеты будут поддерживать оба этих подхода, поскольку 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

Без этого будет обрабатываться только последнее значение в коллекции объектов.

...