在 PowerShell 中按名称设置嵌套对象属性的值

问题描述 投票:0回答:3

我想使用 PowerShell 设置嵌套对象属性的值。当您尝试设置第一级属性的值时,非常简单:

$propertyName = "someProperty"
$obj.$propertyName = "someValue"  # ← It works

对于嵌套属性,它不起作用:

$propertyName = "someProperty.someNestedProperty"
$obj.$propertyName = "someValue"  # ← It doesn't work and raises an error.

如何使用 PowerShell 通过属性名称设置嵌套对象属性的值?

MCVE

对于那些想要重现问题的人,这里有一个简单的例子:

$Obj= ConvertFrom-Json '{ "A": "x", "B": {"C": "y"} }'
# Or simply create the object:
# $Obj= @{ A = "x"; B = @{C = "y"} }
$Key = "B.C"
$Value = "Some Value"
$Obj.$Key = $Value

运行命令,你会收到一个错误:

“在此对象上找不到属性‘B.C’。请验证 属性存在并且可以设置。”

注意:代码支持任意级别的嵌套。

powershell anonymous-types powershell-cmdlet object-graph
3个回答
15
投票

我创建了

SetValue
GetValue
函数,让您可以通过名称动态获取和设置对象(包括 json 对象)的嵌套属性,并且它们工作得很好!

它们是递归函数,通过拆分嵌套属性名称来解析复杂属性并逐步获取嵌套属性。

按名称获取嵌套属性的 GetValue 和 SetValue

# Functions
function GetValue($object, $key)
{
    $p1,$p2 = $key.Split(".")
    if($p2) { return GetValue -object $object.$p1 -key $p2 }
    else { return $object.$p1 }
}
function SetValue($object, $key, $Value)
{
    $p1,$p2 = $key.Split(".")
    if($p2) { SetValue -object $object.$p1 -key $p2 -Value $Value }
    else { $object.$p1 = $Value }
}

示例

在下面的示例中,我使用

B.C
动态设置
SetValue
并使用
GetValue
函数按名称获取其值:

# Example
$Obj = ConvertFrom-Json '{ "A": "x", "B": {"C": "y"} }'
# Or simply create the object:
# $Obj = @{ A = "x"; B = @{C = "y"} }
$Key = "B.C"
$Value = "Changed Dynamically!"
SetValue -object $Obj -key $Key -Value $Value
GetValue -object $Obj -key $Key

4
投票

您的自己的解决方案是有效的,但不支持索引访问作为嵌套属性访问路径的一部分(例如,

B[1].C

一个简单的替代方法是使用 Invoke-Expression

 (
iex
)
。 虽然它
通常应该避免,但在某些特殊情况下它提供了最简单的解决方案,这就是其中之一:

假设您完全控制或隐式信任属性访问字符串:

$obj = ConvertFrom-Json '{ "A": "x", "B": [ {"C": "y"}, { "C": "z"} ] }' $propPath = 'B[1].C' # GET Invoke-Expression "`$obj.$propPath" # -> 'z' # SET $value = 'Some Value' Invoke-Expression "`$obj.$propPath = `$value"

如果您信任输入,您可以避免不必要的命令注入,如下所示:[1]

$safePropPath = $propPath -replace '`|\$', '`$&' Invoke-Expression "`$obj.$safePropPath" # ...
对于安全封装上述功能的

便捷功能/ETS方法,请参阅这个答案


[1] 基于 regex-replace

 操作可确保字符串中的任何 $
 字符都转义为 
`$
,以防止 
Invoke-Expression
 将它们视为变量引用或子表达式;同样,预先存在的 
`
 实例可以通过 
加倍 来转义。


3
投票
我可以建议升级 Reza 的解决方案吗?通过这个解决方案,您可以拥有许多级别的嵌套属性。

function GetValue($object, [string[]]$keys) { $propertyName = $keys[0] if($keys.count.Equals(1)){ return $object.$propertyName } else { return GetValue -object $object.$propertyName -key ($keys | Select-Object -Skip 1) } } function SetValue($object, [string[]]$keys, $value) { $propertyName = $keys[0] if($keys.count.Equals(1)) { $object.$propertyName = $value } else { SetValue -object $object.$propertyName -key ($keys | Select-Object -Skip 1) -value $value } }

用法

$Obj = ConvertFrom-Json '{ "A": "x", "B": {"C": {"D" : "y"}} }' SetValue $Obj -key "B.C.D".Split(".") -value "z" GetValue $Obj -key "B.C.D".Split(".")
    
© www.soinside.com 2019 - 2024. All rights reserved.