代码之家  ›  专栏  ›  技术社区  ›  cyborg

用变量间接访问PSObject属性

  •  2
  • cyborg  · 技术社区  · 7 年前

    假设我有JSON,比如:

      {
        "a" : {
            "b" : 1,
            "c" : 2,
            }
      }
    

    ConvertTo-Json 会快乐地创造 PSObjects 别这样。我想访问一个我能做的项目 $json.a.b 得到1个嵌套良好的属性。

    "a.b" 问题是如何使用该字符串访问该结构中的同一项?好像我少了一些特殊的语法 & Get-Member 我反复期待。

    1 回复  |  直到 7 年前
        1
  •  9
  •   mklement0    6 年前

    不,有 .

    最简单的解决方案是 Invoke-Expression ,如下所示, Invoke-Expression should generally be avoided 在这个特定的场景中 ,因为您完全控制了输入字符串,但最好养成 使用 调用表达式

    $json = @'
    {
      "a" : {
          "b" : 1,
          "c" : 2,
          }
    }
    '@
    
    $obj = ConvertFrom-Json $json
    
    # The path to the target property.
    $propertyPath = 'a.b'
    
    # NOTE: In general, AVOID Invoke-Expression
    # Construct the expression and pass it to Invoke-Expression.
    # Note the need to `-escape the `$` in `$obj` to prevent premature expansion.
    Invoke-Expression "`$obj.$propertyPath"
    

    以上是执行 $obj.a.b. 直接和收益 1


    或者 ,你可以写一个简单的

    function propByPath($obj, $propertyPath) {
      foreach ($prop in $propertyPath -split '\.')  { $obj = $obj.$prop }
      $obj # output
    }
    

    而不是 调用表达式 打电话给您,然后使用:

    propByPath $obj $propertyPath
    

    你甚至可以 (扩展类型系统)到 附加 .GetPropByPath() [pscustomobject] 实例 ( 语法;在PSv2中,必须创建 *.types.ps1xml Update-TypeData -PrependPath ):

    'System.Management.Automation.PSCustomObject',
    'Deserialized.System.Management.Automation.PSCustomObject' |
      Update-TypeData -TypeName { $_ } `
                      -MemberType ScriptMethod -MemberName GetPropByPath -Value {                  #`
        param($propPath)
        $obj = $this
        foreach ($prop in $propPath -split '\.')  { $obj = $obj.$prop }
        $obj # output
      }
    

    $obj.GetPropByPath('a.b') .

    注意 Deserialized.System.Management.Automation.PSCustomObject 除了 System.Management.Automation.PSCustomObject 为了也包括 自定义对象,在许多情况下返回,例如使用 Import-CliXml ,从后台作业接收输出,并使用远程处理。

    将在任何 [pscustomobject] Update-TypeData 呼叫 [一] );放置 Update-TypeData 打电话给你 $PROFILE (配置文件)使方法在默认情况下可用。


    更强大的解决方案,支持 标引 保存 数组值属性 像这样的

    • 不支持 指数 作为属性路径的一部分(例如。, 'a.b[2]' )
    • 使用管道逻辑展开数组值属性,这意味着 单一的

    以下解决方案修复了这些限制,但请注意:

    • 文字,标量 支持索引(也就是说,您可以使用 'a.b[2]' ,但不是 'a.b[1..2]' 'a.b[1, 2]'

    • 对于哈希表属性,请指定(文字)键名称 没有 嵌入报价(例如。, 'a.ht[bar]' 数字 一般来说,哈希表键,另外,您将无法访问 命令 哈希表条目依据 指数 .

    'System.Management.Automation.PSCustomObject',
    'Deserialized.System.Management.Automation.PSCustomObject' |
      Update-TypeData -TypeName { $_ } `
                      -MemberType ScriptMethod -MemberName GetPropByPath -Value {                  #`
        param($propPath)
        $obj = $this
        foreach ($prop in $propPath -split '\.')  {
          # See if the property spec has an index (e.g., 'foo[3]')
          if ($prop -match '(.+?)\[(.+?)\]$') {
            $obj = $obj.($Matches.1)[$Matches.2]
          } else {
            $obj = $obj.$prop
          }
        }
        # Output: If the value is a collection (array), output it as a
        #         *single* object.
        if ($obj.Count) {
          , $obj
        } else {
          $obj
        }
      }
    

    [1] 验证方式(全部在线) $co = New-Object PSCustomObject; Update-TypeData -TypeName System.Management.Automation.PSCustomObject -MemberType ScriptMethod -MemberName GetFoo -Value { 'foo' }; $co.GetFoo() ,其中输出 foo $co 以前创建的 更新类型数据

    推荐文章