Powershell函数从管道接收多个参数

Powershell function receiving multiple parameters from pipeline

我正在写一个函数如下:

Function Display-ItemLocation {
   Param(
      [ Parameter ( 
         Mandatory   = $True,
         Valuefrompipeline = $True ) ]
         [ String ]$stringItem,
      [ Parameter ( 
         Mandatory   = $False,
         Valuefrompipeline = $True ) ]
         [ String ]$stringLocation = 'unknown' 
   )
     Echo "The location of item $stringItem is $stringLocation."
}

Display-ItemLocation 'Illudium Q-36 Explosive Space Modulator' 'Mars'
Display-ItemLocation 'Plumbus'

写的很好。

The location of item Illudium Q-36 Explosive Space Modulator is Mars.
The location of item Plumbus is unknown.

我希望能够预加载包含多个数据对的数组,然后通过管道将其发送到函数中。

$Data = @(
           @('Bucket','Aisle 1'),
           @('Spinach Pie','Freezer 4')
         )
$Data | Display-ItemLocation

我找不到使它起作用的神奇语法。函数可以同时从管道接受一对值吗?

将您的 pipeline-binding 参数定义为通过 属性 name - ValuefromPipelineByPropertyName - 然后管道(自定义)绑定具有此类属性的对象:

Function Display-ItemLocation {
   Param(
      [ Parameter ( 
         Mandatory,
         ValuefromPipelineByPropertyName ) ]
         [ String ]$stringItem,
      [ Parameter ( 
         Mandatory = $False,
         ValuefromPipelineByPropertyName ) ]
         [ String ]$stringLocation = 'unknown' 
   )
   
   process { # !! You need a `process` block to process *all* input objects.
     Echo "The location of item $stringItem is $stringLocation."
   }

}

顺便说一句:Display 不是 PowerShell 中的 approved verb

现在您可以按如下方式通过管道传递给该函数;请注意,属性 名称必须与参数名称匹配:

$Data = [pscustomobject] @{ stringItem = 'Bucket'; stringLocation = 'Aisle 1' },
        [pscustomobject] @{ stringItem = 'Spinach Pie'; stringLocation = 'Freezer 4' }

$Data | Display-ItemLocation

以上结果:

The location of item Bucket is Aisle 1.
The location of item Spinach Pie is Freezer 4.

  • 上面使用了[pscustomobject]个实例,很容易即兴构造

    • 注意哈希表(例如,只是@{ stringItem = 'Bucket'; stringLocation = 'Aisle 1' } not work - 尽管正在 this GitHub issue.
    • 中讨论更改
  • 在 PSv5+ 中,您可以 或者定义自定义 class:

# Define the class.
class Product {
  [string] $stringItem
  [string] $stringLocation
  Product([object[]] $itemAndLocation) { 
    $this.stringItem = $itemAndLocation[0]
    $this.stringLocation = $itemAndLocation[1]
  }
}

# Same output as above.
[Product[]] (
  ('Bucket', 'Aisle 1'), 
  ('Spinach Pie', 'Freezer 4')
) | Display-ItemLocation

感谢@mklement0 引导我找到这个解决方案。我想出了两个选项来使用数组解决我的困境。

方案一:使用.ForEach按常规方式传递参数

$Data = @(
           @('Bucket','Aisle 1'),
           @('Spinach Pie','Freezer 4')
         )

$Data.ForEach({Format-ItemLocation "$($_[0])" "$($_[1])"})

选项 2:使用管道(这正是我所追求的),我按照 mklement0 的建议修改了函数以启用 ValuefromPipelineByPropertyName 并包含一个 Process { }块。

Function Format-ItemLocation {
   Param (
      [ Parameter ( 
         Mandatory   = $True,
         ValuefromPipelineByPropertyName = $True ) ]
         [ String ]$stringItem,
      [ Parameter ( 
         Mandatory   = $False,
         ValuefromPipelineByPropertyName = $True ) ]
         [ String ]$stringLocation = 'unknown' 
   )
   Process {
       "The location of item $stringItem is $stringLocation."
   }
} 

我通过管道将数组传递到中间步骤以将参数名称分配给 [PSCustomObject]。这大大减少了会使代码变大的文本量,这也是我寻找更优雅的解决方案的原因。

$Data = @(
           @('Bucket','Aisle 1'),
           @('Spinach Pie','Freezer 4')
         )

$Data | 
   ForEach-Object { [PSCustomObject]@{stringItem=$_[0];stringLocation=$_[1]} } |
   Format-ItemLocation

我按照推荐把函数名改成了Format-*