PSCustomObject数组和ValueFromPipelineByPropertyName

时间:2013-12-04 20:44:18

标签: powershell powershell-v3.0

背景:我有一些我希望更容易访问的位置。我不想mklink,因为这样可能会将路径保存为链接路径并稍后失败。

建议的解决方案:创建一些PSDrives。从静态的哈希表数组开始,以便将来可以轻松导入/导出/过滤它们。

准备步骤:

# Clear out existing drives, empty error stack
Get-PSDrive -name "*-test-*" | Remove-PSDrive 
$Error.Clear()

解决方案1失败:使用参数KVP

创建哈希数组
@(
    @{ Name='hasharray-test-control'; Root='C:\Windows\Temp' },
    @{ Name='hasharray-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | New-PSDrive -PSProvider FileSystem

混淆错误"输入对象无法绑定到命令的任何参数..."

解决方案2失败:Web-grokking显示项目必须是PSCustomObject,而不是哈希

@(
    [PSCustomObject]@{ Name='array-test-control'; Root='C:\Windows\Temp' },
    [PSCustomObject]@{ Name='array-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | New-PSDrive -PSProvider FileSystem

使用

在第二项上失败
New-PSDrive : Cannot bind parameter 'Name' to the target. 
Exception setting "Name": 
    "Cannot process argument because the value of argument "value" is null.

失败解决方案3:好的,也许powershell将数组作为一个大blob传递,使其隐式

[PSCustomObject]@{ Name='implicitarray-test-control'; Root='C:\Windows\Temp' },
[PSCustomObject]@{ Name='implicitarray-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" } |
    New-PSDrive -PSProvider FileSystem

第二项错误

失败

失败的解决方案4:插入中间变量

$TestDrives = @(
    [PSCustomObject]@{ Name='foreach-test-control'; Root='C:\Windows\Temp' }
    [PSCustomObject]@{ Name='foreach-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) 
$TestDrives | New-PSDrive -PSProvider FileSystem

第二项错误

失败

失败的解决方案5:插入选择以提取属性

@(
    [PSCustomObject]@{ Name='select-test-control'; Root='C:\Windows\Temp' },
    [PSCustomObject]@{ Name='select-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | Select Name, Root | New-PSDrive -PSProvider FileSystem

第二项错误

失败

解决方案6失败:不是吗?好的,我将添加foreach以强制解决每个项目

$TestDrives = @(
    [PSCustomObject]@{ Name='foreachpipe-test-control'; Root='C:\Windows\Temp' },
    [PSCustomObject]@{ Name='foreachpipe-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) 
$TestDrives | ForEach-Object { $_ } | New-PSDrive -PSProvider FileSystem 

第二项错误

失败

解决方案7失败:仍然没有?好的,在foreach

中明确选择每个属性
@(
    [PSCustomObject]@{ Name='foreachselect-test-control'; Root='C:\Windows\Temp' },
    [PSCustomObject]@{ Name='foreachselect-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | ForEach-Object { $_ | Select Name, Root } | New-PSDrive -PSProvider FileSystem

第二项错误

失败

为了好的衡量,我们只尝试静态值:

@(
    [PSCustomObject]@{ Name='foreachstatic-test-control'; Root='C:\Windows\Temp' }
    [PSCustomObject]@{ Name='foreachstatic-test-control-2'; Root='C:\Windows\Temp' }
) | New-PSDrive -PSProvider FileSystem

第二项错误

失败

额外说明:

  • 我尝试了两者,并且在数组声明中没有逗号,结果是相同的
  • 我也尝试了以下作为第二项,结果相同
    • [PSCustomObject]@{ Name='test-interp'; Root="$HOME\Temp" }
    • [PSCustomObject]@{ Name='test-interp-command'; Root="$($HOME)\Temp" }
    • [PSCustomObject]@{ Name='test-format'; Root=('{0}\Temp' -f $HOME) }
    • [PSCustomObject]@{ Name='test-format-resolve'; Root=$('{0}\Temp' -f $HOME) }
    • 设置$tRoot外部哈希值,并使用[PSCustomObject]@{ Name='test-format-resolve'; Root=$tRoot }

工作解决方案:哇,我说不出话来......让我们围绕着所有事情强行推进

@(
    [PSCustomObject]@{ Name='foreach-test-control'; Root='C:\Windows\Temp' },
    [PSCustomObject]@{ Name='foreach-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | ForEach-Object { $_ | New-PSDrive -PSProvider FileSystem }

现在它有效,但感觉不对,因为它已经在管道上了。

现在,问题是: 当New-PSDrive支持ValueFromPipelineByPropertyNameName的{​​{1}}时,为什么我必须在这种情况下显式地使用ForEach-Object而不是能够使用管道?

为什么每个数组中的第一项都有效,而所有后续项目都失败了?

2 个答案:

答案 0 :(得分:3)

你在实施New-PSDrive时遇到了一个错误。

Name / Root / PSDrive参数的属性设置器未正确编写以支持管道中的多个对象。

答案 1 :(得分:2)

这是New-PSDrive cmdlet的问题,因为atm。它一次只支持一个对象。 Remove-PSDrive确实支持数组输入,这表明它也应该包含在New-PSDrive中(就像PS-cmdlet应该可以工作一样)。要验证它是否是cmdlet的错误,您可以运行以下命令来查看它是如何正确绑定第一个对象的属性的,而它在第二个对象的开头取消。

Trace-Command -Expression { 
@(
    [PSCustomObject]@{ Name='array-test-control'; Root='C:\Windows\Temp' },
    [PSCustomObject]@{ Name='array-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | New-PSDrive -PSProvider FileSystem
} -Name ParameterBinding -PSHost

输出部分:

#First object
 BIND PIPELINE object to parameters: [New-PSDrive]
DEBUG: ParameterBinding Information: 0 :     PIPELINE object TYPE = [System.Management.Automation.PSCustomObject]
DEBUG: ParameterBinding Information: 0 :     RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 :     Parameter [Name] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [hasharray-test-interp-brace] to parameter [Name]
DEBUG: ParameterBinding Information: 0 :         BIND arg [hasharray-test-interp-brace] to param [Name] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 :     Parameter [Root] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [C:\Windows\Temp] to parameter [Root]
DEBUG: ParameterBinding Information: 0 :         BIND arg [C:\Windows\Temp] to param [Root] SUCCESSFUL


#Second object
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [New-PSDrive]
DEBUG: ParameterBinding Information: 0 :     PIPELINE object TYPE = [System.Management.Automation.PSCustomObject]
DEBUG: ParameterBinding Information: 0 :     RESTORING pipeline parameter's original values
#It now skips right to the result(error) without trying to bind the parameters.
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Out-Default]