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

时间:2017-09-27 15:38:40

标签: powershell anonymous-types cmdlet

我想使用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'在这个对象上找不到。验证   属性存在且可以设置。"

3 个答案:

答案 0 :(得分:4)

我创建了SetValueGetValue方法,让您通过名称动态获取和设置对象(包括json对象)的嵌套属性,并且它们完美无缺!

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

按名称划分的嵌套属性的GetValue和SetValue

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

答案 1 :(得分:1)

我可以提出对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(".")

答案 2 :(得分:1)

您的own solutions 是有效的,但不支持将索引访问作为嵌套属性访问路径的一部分(例如, from itertools import permutations while True: numnum = input('Please choose number of cards (enter anything other than 4 and 5 to quit the program):') if numnum == '4': try: a = int(input("Please enter the first number:")) b = int(input("Please enter the second number:")) c = int(input("Please enter the third number:")) d = int(input("Please enter the fourth number:")) except: print('WARNING: Please enter a real number!') continue print('Processing...') my_list = [a, b, c, d] # Randomly arrange a list of 4 integers result = [c for c in permutations(my_list, 4)] symbols = ["+", "-", "*", "/"] list2 = [] # Calculate the list of 24 permutations and combinations flag = False for one, two, three, four in result: for s1 in symbols: for s2 in symbols: for s3 in symbols: if s1 + s2 + s3 in ['+++', '***', '+--', '++-', '**/', '*//', '///']: express = ["{0}{1}{2}{3}{4}{5}{6}".format(one, s1, two, s2, three, s3, four)] elif s1 + s2 + s3 in ['+-+', '-++', '-+-', '--+', '*/*', '/**', '/*/', '//*']: continue else: express = ["({0}{1}{2}){3}{4}{5}{6}".format(one, s1, two, s2, three, s3, four), "({0}{1}{2}{3}{4}){5}{6}".format(one, s1, two, s2, three, s3, four), "{0}{1}({2}{3}{4}){5}{6}".format(one, s1, two, s2, three, s3, four), "{0}{1}({2}{3}{4}{5}{6})".format(one, s1, two, s2, three, s3, four), "{0}{1}{2}{3}({4}{5}{6})".format(one, s1, two, s2, three, s3, four), "(({0}{1}{2}){3}{4}){5}{6}".format(one, s1, two, s2, three, s3, four), "({0}{1}{2}){3}({4}{5}{6})".format(one, s1, two, s2, three, s3, four), "({0}{1}({2}{3}{4})){5}{6}".format(one, s1, two, s2, three, s3, four), "{0}{1}(({2}{3}{4}){5}{6})".format(one, s1, two, s2, three, s3, four), "{0}{1}({2}{3}({4}{5}{6}))".format(one, s1, two, s2, three, s3, four)] for e in express: try: if eval(e) == 24: list2.append(e) flag = True except ZeroDivisionError: pass for c in list2: if '+(' in c or '-(' in c or ')-' in c or ')+' in c or ')*' in c: continue print(c) if not flag: print("NO solution...") elif numnum == '5': try: a = int(input("Please enter the first number:")) b = int(input("Please enter the second number:")) c = int(input("Please enter the third number:")) d = int(input("Please enter the fourth number:")) e = int(input('Please enter the fifth number:')) except: print('WARNING: Please enter a real number!') continue print('Processing...') my_list = [a, b, c, d, e] # Randomly arrange a list of 4 integers result = [c for c in permutations(my_list, 5)] symbols = ["+", "-", "*", "/"] list2 = [] # Calculate the list of 24 permutations and combinations flag = False for one, two, three, four, five in result: for s1 in symbols: for s2 in symbols: for s3 in symbols: for s4 in symbols: if s1 + s2 + s3 + s4 in ['++++', '****', '+---', '+++-', '++--', '**//', '*///', '///', '***/']: express = ["{0}{1}{2}{3}{4}{5}{6}{7}{8}".format(one, s1, two, s2, three, s3, four, s4, five)] elif (s1, s2, s3, s4) in permutations(['*', '/', '/', '/']) \ or (s1, s2, s3, s4) in permutations(['*', '*', '/', '/']) \ or (s1, s2, s3, s4) in permutations(['*', '*', '*', '/']) \ or (s1, s2, s3, s4) in permutations(['+', '-', '-', '-']) \ or (s1, s2, s3, s4) in permutations(['+', '+', '-', '-']) \ or (s1, s2, s3, s4) in permutations(['+', '+', '+', '-']): continue else: express = ["({0}{1}{2}){3}{4}{5}{6}{7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}{2}{3}{4}){5}{6}{7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}{2}{3}{4}{5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}{4}){5}{6}{7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}{4}{5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}{4}{5}{6}{7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}{2}{3}({4}{5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}{2}{3}({4}{5}{6}{7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}{2}{3}{4}{5}({6}{7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "(({0}{1}{2}){3}{4}){5}{6}{7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "(({0}{1}{2}){3}{4}{5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}{2}){3}({4}{5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}{2}){3}({4}{5}{6}{7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}{2}){3}{4}{5}({6}{7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}{2}{3}{4}){5}({6}{7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "(({0}{1}{2}{3}{4}){5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}({2}{3}{4})){5}{6}{7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}({2}{3}{4}){5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}{2}{3}({4}{5}{6})){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}({2}{3}{4}{5}{6})){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}(({2}{3}{4}){5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}(({2}{3}{4}){5}{6}{7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}{4}){5}({6}{7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}({4}{5}{6})){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}(({2}{3}{4}{5}{6}){7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}({4}{5}{6}){7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}({4}{5}{6}{7}{8}))".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}{4}{5}({6}{7}{8}))".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}{2}{3}(({4}{5}{6}){7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}{2}{3}({4}{5}({6}{7}{8}))".format(one, s1, two, s2, three, s3, four, s4, five), "((({0}{1}{2}){3}{4}){5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "(({0}{1}{2}){3}({4}{5}{6})){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}{2}){3}(({4}{5}{6}){7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}{2}){3}({4}{5}({6}{7}{8}))".format(one, s1, two, s2, three, s3, four, s4, five), "(({0}{1}({2}{3}{4})){5}{6}){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}({2}{3}{4})){5}({6}{7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}(({2}{3}{4}){5}{6})){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "({0}{1}({2}{3}({4}{5}{6}))){7}{8}".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}((({2}{3}{4}){5}{6}){7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}(({2}{3}{4}){5}({6}{7}{8}))".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}(({2}{3}({4}{5}{6})){7}{8})".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}(({4}{5}{6}){7}{8}))".format(one, s1, two, s2, three, s3, four, s4, five), "{0}{1}({2}{3}({4}{5}({6}{7}{8})))".format(one, s1, two, s2, three, s3, four, s4, five)] for e in express: try: if eval(e) == 24: list2.append(e) flag = True except ZeroDivisionError: pass for c in list2: if '+(' in c or '-(' in c or ')-' in c or ')+' in c or ')*' in c: continue print(c) if not flag: print("NO solution...") else: break

一个简单的替代方法是使用B[1].C (Invoke-Expression)。 虽然它should generally be avoided,但在特殊情况下它提供了最简单的解决方案,这就是其中之一:

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

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" 

有关安全打包上述功能的便利功能/ETS 方法,请参阅this answer