PowerShell 7.4中同时使用ValueFromPipeline与ValueFromPipelineByPropertyName的问题
解决PowerShell函数同时支持管道字符串与结构化对象输入的问题
问题分析
你遇到的核心问题有两个:
- 管道输入的数组未展开:测试输入中
('c:\temp\songB.mp3', 'c:\temp\songC.mp3')是作为单个数组对象传入管道的,而非两个独立的字符串元素,导致函数一次接收整个数组而非逐个处理。 - 参数绑定与输入类型判断逻辑错误:同时启用
ValueFromPipeline和ValueFromPipelineByPropertyName时,若输入是数组,$path会被赋值为整个数组;若输入是带匹配属性的对象,直接判断类型为非字符串后取Fullname的逻辑,无法覆盖数组内的字符串元素。
正确实现方式
以下函数可同时支持管道传入单个/多个字符串路径、带FullName(或别名fullname)属性的结构化对象,以及两种类型的混合输入:
function Set-FooBarPlayer { [CmdletBinding()] Param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('Fullname')] $Path ) process { # 处理集合类型输入(如数组),逐个展开元素处理 if ($Path -is [System.Collections.IEnumerable] -and $Path -isnot [string]) { foreach ($item in $Path) { $item | Set-FooBarPlayer } return } # 提取路径:存在FullName属性则取属性值,否则直接返回输入值 if ($Path.PSObject.Properties['FullName']) { $Path.FullName } else { $Path } } }
测试验证
使用你提供的输入(函数会自动处理数组展开):
[pscustomobject]@{fullname = 'c:\temp\songA.mp3' ; length = '00:03:30:070'}, ('c:\temp\songB.mp3', 'c:\temp\songC.mp3') | Set-FooBarPlayer
输出结果完全符合预期:
c:\temp\songA.mp3 c:\temp\songB.mp3 c:\temp\songC.mp3
关键逻辑说明
- 集合展开:通过判断输入是否为非字符串的可枚举对象,递归调用函数处理每个元素,确保数组内的每个路径都被单独解析。
- 安全提取属性:使用
PSObject.Properties检查对象是否包含FullName属性,避免直接访问属性导致的空值错误,同时兼容字符串直接返回的场景。
内容的提问来源于stack exchange,提问作者Ralf_Reddings
相关产品推荐
相关产品推荐

