Задать значение свойства вложенного объекта по имени в 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
Запустите команду, и вы получите ошибку:
"Свойство" BC "не может быть найдено для этого объекта. Убедитесь, что свойство существует и может быть установлено".
3 ответа
Я создал SetValue
а также GetValue
методы, позволяющие динамически получать и устанавливать вложенное свойство объекта (включая объект 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
Ваши собственные решения эффективны, но не поддерживают индексированный доступ как часть вложенного пути доступа к свойствам (например,
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 '(`)*\$', '$1$1`$$'
Invoke-Expression "`$obj.$safePropPath"
# ...
Информацию об удобной функции / методе ETS, который безопасно упаковывает вышеперечисленные функции , см. В этом ответе .
Могу я предложить обновление решения Резы. С помощью этого решения вы можете иметь много уровней вложенных свойств.
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(".")