【问题标题】:PSCustomObject array and ValueFromPipelineByPropertyNamePSCustomObject 数组和 ValueFromPipelineByPropertyName
【发布时间】:2013-12-21 12:55:34
【问题描述】:

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

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

准备步骤:

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

失败的解决方案 1:使用参数 KVPs 创建哈希数组

@(
    @{ 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 }

可行的解决方案:哇,我无语了...让我们在所有事情上强制一个 foreach

@(
    [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 支持ValueFromPipelineByPropertyName 用于NameRoot 时,为什么在这种情况下我必须显式地使用 ForEach-Object 而不能使用管道?

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

【问题讨论】:

  • +1。那是很多尝试。这似乎是一个很好的问题。我会把它留给 Powershell 专家。

标签: powershell powershell-3.0


【解决方案1】:

您在 New-PSDrive 的实现中遇到了一个错误。

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

【讨论】:

    【解决方案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]
    

    【讨论】:

    • 我已经提交了一个关于连接的错误。如果可以确认该错误的人会支持它,那将有很大帮助。反馈编号:810712
    • 我不知道Trace-Command,只知道Set-PSDebug。另外,感谢您打开 Connect 项目,如果我能够像您一样证明错误,我会这样做的。
    猜你喜欢
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多