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

Set Value of Nested Object Property by Name in PowerShell

我想使用 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

运行 命令,您将收到错误消息:

"The property 'B.C' cannot be found on this object. Verify that the property exists and can be set."

注意:代码支持任意层级嵌套

我创建了 SetValueGetValue 函数,让您可以通过名称动态获取和设置对象(包括 json 对象)的嵌套 属性,它们工作完美!

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

按名称获取嵌套属性的值和设置值

# 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 }
}

例子

在下面的示例中,我使用 SetValue 动态设置 B.C 并使用 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

我可以提议升级 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(".")

您的 有效,但不支持 indexed access 作为嵌套 属性 的一部分-访问路径(例如,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" 

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

$safePropPath = $propPath -replace '(`)*$', '`$$'
Invoke-Expression "`$obj.$safePropPath"
# ...

对于安全打包上述功能的便捷功能/ETS 方法,请参阅