使用变量间接访问 PSObject 属性 [英] Access PSObject property indirectly with variable

查看:41
本文介绍了使用变量间接访问 PSObject 属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有这样的 JSON:

Say I have JSON like:

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

现在 ConvertTo-Json 会很高兴地从中创建 PSObjects.我想访问一个我可以做的项目 $json.a.b 并获得 1 - 很好的嵌套属性.

Now ConvertTo-Json will happily create PSObjects out of that. I want to access an item I could do $json.a.b and get 1 - nicely nested properties.

现在如果我有字符串 "a.b" 问题是如何使用该字符串访问该结构中的相同项目?似乎应该有一些我缺少的特殊语法,例如用于动态函数调用的 & ,否则您必须重复使用 Get-Member 自己解释字符串,我期望.

Now if I have the string "a.b" the question is how to use that string to access the same item in that structure? Seems like there should be some special syntax I'm missing like & for dynamic function calls because otherwise you have to interpret the string yourself using Get-Member repeatedly I expect.

推荐答案

没有,没有特殊语法.

No, there is no special syntax.

虽然最简单的解决方案是使用 Invoke-Expression,但如下所示,Invoke-Expression 通常应该避免在这种特殊情况下是安全的,因为你完全控制输入字符串,但最好养成使用Invoke-Expression,特别是考虑到在大多数情况下都有更强大和更安全的替代方案:

While the simplest solution is to use Invoke-Expression, as shown next, Invoke-Expression should generally be avoided; it is safe in this particular scenario, because you fully control the input string, but it is better to form a habit of not using Invoke-Expression, especially given that in most situations there are alternatives that are both more robust and more secure:

$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.

The above is the equivalent of executing $obj.a.b. directly and yields 1.

或者,您可以编写一个简单的辅助函数:

Alternatively, you could write a simple helper function:

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

您将使用:

propByPath $obj $propertyPath

<小时>

您甚至可以使用 PowerShell 的 ETS(扩展类型系统)来.GetPropByPath() 方法附加到所有 [pscustomobject]> 实例(PSv3+ 语法;在 PSv2 中,您必须创建一个 *.types.ps1xml 文件并使用 Update-TypeData 加载它 -PrependPath):


You could even use PowerShell's ETS (extended type system) to attach a .GetPropByPath() method to all [pscustomobject] instances (PSv3+ syntax; in PSv2 you'd have to create a *.types.ps1xml file and load it with 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').

注意:除了 System.Management.Automation.PSCustomObject 之外,还有目标类型 Deserialized.System.Management.Automation.PSCustomObject还涵盖反序列化自定义对象,这些对象在许多场景中返回,例如使用 Import-CliXml、从后台作业接收输出以及使用远程处理.

Note: Type Deserialized.System.Management.Automation.PSCustomObject is targeted in addition to System.Management.Automation.PSCustomObject in order to also cover deserialized custom objects, which are returned in a number of scenarios, such as using Import-CliXml, receiving output from background jobs, and using remoting.

.GetPropByPath() 将在会话的剩余部分中的任何 [pscustomobject] 实例上可用(即使在 Update-TypeData 之前创建的实例上) 调用 [1]);放置 Update-TypeData 调用您的 $PROFILE(配置文件)以使该方法默认可用.

.GetPropByPath() will be available on any [pscustomobject] instance in the remainder of the session (even on instances created prior to the Update-TypeData call [1]); place the Update-TypeData call in your $PROFILE (profile file) to make the method available by default.

更强大的解决方案,支持索引并保留数组值属性

A more robust solution that supports indexing and preserves array-valued properties as such

以上解决方法:

  • 不支持将索引作为属性路径的一部分(例如,'a.b[2]')
  • 使用管道逻辑展开数组值属性,这意味着单个元素数组被展开为其唯一的元素.
  • doesn't support indices as part of the property path (e.g., 'a.b[2]')
  • unwraps array-valued properties using pipeline logic, which means that a single-element array is unwrapped to its one and only element.

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

The following solution fixes these limitations, but note that:

  • 仅支持文字、标量索引(也就是说,您可以使用'ab[2]',但不能使用'ab[1..2]''ab[1, 2]',例如)

  • Only literal, scalar indices are supported (that is, you can use 'a.b[2]', but not 'a.b[1..2]' or 'a.b[1, 2]', for instance)

对于哈希表的属性,指定(文字)键名没有嵌入引用(例如,'a.ht[bar]');请注意,您通常无法访问数字哈希表键,此外,您将无法访问有序哈希表的条目索引.

For properties that are hashtables, specify the (literal) key name without embedded quoting (e.g., 'a.ht[bar]'); note that you won't be able to access numeric hashtable keys in general, and, additionally, you won't be able to access an ordered hashtable's entries by index.

'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(),即使 $co 是在调用 Update-TypeData 之前创建的,它也会输出 foo.上>


[1] Verify with (all on one line) $co = New-Object PSCustomObject; Update-TypeData -TypeName System.Management.Automation.PSCustomObject -MemberType ScriptMethod -MemberName GetFoo -Value { 'foo' }; $co.GetFoo(), which outputs foo even though $co was created before Update-TypeData was called.

这篇关于使用变量间接访问 PSObject 属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆