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

问题描述

我正在编写如下函数:

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

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

解决方法

使用属性 -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' }不起作用-尽管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将我引向这个解决方案。我想出了两个选择来解决使用数组的困境。

选项1 :使用.ForEach以通常的方式传递参数。

$Data = @(
           @('Bucket',@('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','Freezer 4')
         )

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

我已根据建议将函数名称更改为Format-*

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...