Как получить доступ к переменной powershell PSCustomObject с помощью переменной (из json)

У меня есть PSCustomObject, у которого есть список подобъектов, подобных этому:

vmssSystemUpdatesMonitoringEffect                                   : @{type=String; metadata=; allowedValues=System.Object[]; defaultValue=AuditIfNotExists}
vmssEndpointProtectionMonitoringEffect                              : @{type=String; metadata=; allowedValues=System.Object[]; defaultValue=AuditIfNotExists}
vmssOsVulnerabilitiesMonitoringEffect                               : @{type=String; metadata=; allowedValues=System.Object[]; defaultValue=AuditIfNotExists}
systemUpdatesMonitoringEffect                                       : @{type=String; metadata=; allowedValues=System.Object[]; defaultValue=AuditIfNotExists}
systemConfigurationsMonitoringEffect                                : @{type=String; metadata=; allowedValues=System.Object[]; defaultValue=AuditIfNotExists}

и т. д.

Часть объекта в формате JSON:

{
  "vmssSystemUpdatesMonitoringEffect": {
    "type": "String",
    "metadata": {
      "displayName": "System updates on virtual machine scale sets should be installed",
      "description": "Enable or disable virtual machine scale sets reporting of system updates"
    },
    "allowedValues": [
      "AuditIfNotExists",
      "Disabled"
    ],
    "defaultValue": "AuditIfNotExists"
  },
  "vmssEndpointProtectionMonitoringEffect": {
    "type": "String",
    "metadata": {
      "displayName": "Endpoint protection solution should be installed on virtual machine scale sets",
      "description": "Enable or disable virtual machine scale sets endpoint protection monitoring"
    },
    "allowedValues": [
      "AuditIfNotExists",
      "Disabled"
    ],
    "defaultValue": "AuditIfNotExists"
  },
  "vmssOsVulnerabilitiesMonitoringEffect": {
    "type": "String",
    "metadata": {
      "displayName": "Vulnerabilities in security configuration on your virtual machine scale sets should be remediated",
      "description": "Enable or disable virtual machine scale sets OS vulnerabilities monitoring"
    },
    "allowedValues": [
      "AuditIfNotExists",
      "Disabled"
    ],
    "defaultValue": "AuditIfNotExists"
  }
}

Ключи, с которыми я получаю доступ к массиву

$Keys = $Hash | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name

Я могу получить ключи в массив и перебрать их, но я не могу получить доступ к свойствам, указав ключ с переменной:

foreach ($key in $Keys) {
        Write-Host "key" $key
        $data = $KeyValue.$key  
}

Результат: ключ aadAuthenticationInServiceFabricMonitoringEffect

и данные пустые

Однако это работает:

$KeyValue.vmssSystemUpdatesMonitoringEffect

И это:

$key= "aadAuthenticationInServiceFabricMonitoringEffect"
$KeyValue.$key

Как я могу заставить это работать с переменной?


person Kamsiinov    schedule 06.02.2020    source источник
comment
Если я посмотрю на $json.vmssEndpointProtectionMonitoringEffect.psobject.Properties.name после импорта вашего json, он сработает... Если вы сделаете .gettype() на aadAuthenticationInServiceFabricMonitoringEffect, какой тип объекта? (поскольку того, с которым у вас проблемы, нет в образце json)   -  person Sage Pourpre    schedule 06.02.2020
comment
Тип объекта — PSCustomObject.   -  person Kamsiinov    schedule 06.02.2020
comment
Боюсь, что невозможно поставить диагноз, пока не будет предоставлен воспроизводимый образец. PSCustomObject вернет свой член. Возможно, попробуйте Get-Member, чтобы увидеть, могут ли его свойства быть несколько не типа NoteProperty. Также убедитесь, что путь к aadAuthenticationInServiceFabricMonitoringEffect хорош, как если бы вы делали $Keyvalue.aadAuthenticationInServiceFabricMonitoringEffect, а фактический путь был другим, например: $Keyvalue.Me.aadAuthenticationInServiceFabricMonitoringEffect, тогда это объясняет, почему вы не получаете данные.   -  person Sage Pourpre    schedule 06.02.2020
comment
если у вас установлен модуль Azure Az, вы можете запустить: $Policyset = Get-AzPolicySetDefinition -Name 1f3afdf9-d0c9-4c3d-847f-89da613e70a8   -  person Kamsiinov    schedule 06.02.2020
comment
Смотрите мой отредактированный ответ. Это тот же принцип, который я изложил в своем первоначальном ответе, но я использовал именно те команды, которые вы предоставили, и он работает. Дайте мне знать, если я неправильно понял, что вы пытались сделать, или если это сработало, отметьте это как принятое :)   -  person Sage Pourpre    schedule 06.02.2020
comment
Моя цель — перебрать все те параметры, которые у вас есть в переменной policyHash, чтобы я мог получить значения по умолчанию, отображаемые имена и т. д.   -  person Kamsiinov    schedule 06.02.2020
comment
См. дополнительный раздел примечаний, который я добавил. Есть еще один ответ специально для этого бита, который позволит вам пройти через гнездо psobject в цикле.   -  person Sage Pourpre    schedule 06.02.2020
comment
Что такое $keyvalue?   -  person js2010    schedule 06.02.2020


Ответы (3)


Чтобы перебрать свойства PSObject, вам нужно пройтись по свойствам, используя $YourObject.psobject.Properties.Name

См. приведенный ниже пример, основанный на предоставленной вами информации.

$Policyset = Get-AzPolicySetDefinition
$Policyset = Get-AzPolicySetDefinition -Name 1f3afdf9-d0c9-4c3d-847f-89da613e70a8 
$policyHash = $Policyset.Properties.parameters

$DataSet = $policyHash.aadAuthenticationInServiceFabricMonitoringEffect
$Keys = $DataSet.psobject.Properties.name

foreach ($key in $Keys) {
    Write-Host $Key -ForegroundColor Cyan
    Write-Host $DataSet.$key
}

Результат

Результат

Дополнительное примечание. Поскольку вы добавили, что хотите выполнить итерацию по вложенным свойствам, посмотрите приведенный здесь ответ. итерация-по-psobject-свойствам-в-powershell. Обратите внимание на бесконечный цикл из-за ссылки на родительский объект, так как это применимо в вашем случае.

person Sage Pourpre    schedule 06.02.2020
comment
$data = $KeyValue.$key ты имел в виду $item.$key ? - person Mike L'Angelo; 06.02.2020
comment
@MikeL'Angelo Абсолютно. Я отвлеклась. Спасибо за улов :) - person Sage Pourpre; 06.02.2020
comment
Вот как я думаю, это работает. Однако, как я писал в своем вопросе, у меня это почему-то не работает. - person Kamsiinov; 06.02.2020
comment
@Kamsiinov Можете ли вы взять свой объект, использовать на нем Convert-to-Json и добавить это к своему вопросу (после редактирования всего, что не должно быть видно другими значениями)? Будет легко дать точный ответ, если мы увидим фактическую структуру объекта и сможем преобразовать ее обратно в объект. - person Sage Pourpre; 06.02.2020
comment
Я добавил, это JSON. Этот объект выглядит для меня нормальным, но он не ведет себя как обычный объект, так как это PSCustomObject. - person Kamsiinov; 06.02.2020

Предполагая, что у вас есть объект, похожий на этот:

$KeyValue = @{
vmssSystemUpdatesMonitoringEffect = @{
    type='String'; 
    metadata=''; 
    allowedValues=@(1,2,3); 
    defaultValue='AuditIfNotExists'}
}

По сути, у нас есть пара ключ-значение, в которой верхний уровень содержит только один ключ, vmssSystemUpdatesMonitoringEffect, со значением собственной вложенной хеш-таблицы.

Мы можем довольно легко разобрать это, сначала найдя и .Keys в хэш-таблице, а затем foreach из них, ища там любые .Keys и получая их значения.

$KeyValue = @{vmssSystemUpdatesMonitoringEffect = @{type='String'; metadata=''; allowedValues=@(1,2,3); defaultValue='AuditIfNotExists'}}
foreach($key in $KeyValue.Keys){
    $nestedKeys = $KeyValue.$key.Keys
    "parsing node $key in `$KeyValue` which has $($nestedKeys.Count) nested keys"

    foreach($nestedkey in $nestedKeys){
        "--parsing nested key $nestedKey"
        "--$($KeyValue.$key.$nestedKey)"
        }
}

Что даст нам вывод:

parsing node vmssSystemUpdatesMonitoringEffect in $KeyValue which has 4 nested keys
--parsing nested key defaultValue
--AuditIfNotExists
--parsing nested key allowedValues
--1 2 3
--parsing nested key type
--String
--parsing nested key metadata
--

Это должно помочь вам начать путь, который вас интересует.

Если у вас есть PSCustomObject, который содержит хеш-таблицу

Во-первых, мне очень, очень жаль, что ты в конечном итоге испытываешь эту боль.

Во-вторых, вы должны использовать два метода для перечисления узлов вашего нечестивого ублюдка, если вы находитесь в этом случае.

$KeyValue = [pscustomobject]@{vmssSystemUpdatesMonitoringEffect = @{type='String'; metadata=''; allowedValues=@(1,2,3); defaultValue='AuditIfNotExists'}}
$keys = get-member -InputObject $keyvalue -MemberType NoteProperty 
foreach($key in $keys){
    $nestedKeys = $KeyValue.$($key.Name).Keys
    "parsing node $($key.Name) in `$KeyValue` which has $($nestedKeys.Count) nested keys"

    foreach($nestedkey in $nestedKeys){
        "--parsing nested key $nestedKey"
        "--$($KeyValue.$($key.Name).$nestedKey)"
        }
}

Большая разница в том, что мы должны получить все ключи с помощью командлета Get-Member и указать, что мы хотим получить элементы с типом NoteProperty. Это дает нам все свойства CustomObject, которые мы затем пройдем в поисках хэш-таблиц со свойствами.

Следующий набор странностей связан с этой строкой $nestedKeys = $KeyValue.$($key.Name).Keys, в которой используется оператор subExpression PowerShell для запуска элемента в пределах $( )symbols и обработки вывода в виде строки. Это похоже на запуск $KeyValue.vmssSystemUpdatesMonitoringEffect.Keys.

Кроме того, синтаксис в основном такой же.

person FoxDeploy    schedule 06.02.2020
comment
Этот объект является PSCustomObject, поэтому он не работает как обычная пара keyValue. - person Kamsiinov; 06.02.2020
comment
Я обновил пример выполнения этого как объекта PowerShell. - person FoxDeploy; 06.02.2020

В вашем примере, не будет ли это:

$hash = get-content file.json | convertfrom-json
$Keys = $Hash | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name
$data = foreach ($key in $Keys) {
  $hash.$key  
}
$data


type   metadata                     allowedValues
----   --------                     -------------
String @{displayName=Endpoint prote {AuditIfNotExists, Disabled}
String @{displayName=Vulnerabilitie {AuditIfNotExists, Disabled}
String @{displayName=System updates {AuditIfNotExists, Disabled}

Для меня, если с объектом сложно работать, дизайн плохой. Я предпочитаю это так, как массив из 3-х похожих объектов:

[
    {
        "header":  "vmssSystemUpdatesMonitoringEffect",
        "type":  "String",
        "metadata":  {
                         "displayName":  "System updates on virtual machine scale sets should be installed",
                         "description":  "Enable or disable virtual machine scale sets reporting of system updates"
                     },
        "allowedValues":  [
                              "AuditIfNotExists",
                              "Disabled"
                          ],
        "defaultValue":  "AuditIfNotExists"
    },
    {
        "header":  "vmssEndpointProtectionMonitoringEffect",
        "type":  "String",
        "metadata":  {
                         "displayName":  "Endpoint protection solution should be installed on virtual machine scale sets",
                         "description":  "Enable or disable virtual machine scale sets endpoint protection monitoring"
                     },
        "allowedValues":  [
                              "AuditIfNotExists",
                              "Disabled"
                          ],
        "defaultValue":  "AuditIfNotExists"
    },
    {
        "header":  "vmssOsVulnerabilitiesMonitoringEffect",
        "type":  "String",
        "metadata":  {
                         "displayName":  "Vulnerabilities in security configuration on your virtual machine scale sets should be remediated",
                         "description":  "Enable or disable virtual machine scale sets OS vulnerabilities monitoring"
                     },
        "allowedValues":  [
                              "AuditIfNotExists",
                              "Disabled"
                          ],
        "defaultValue":  "AuditIfNotExists"
    }
]

Затем:

cat file.json | convertfrom-json

header        : vmssSystemUpdatesMonitoringEffect
type          : String
metadata      : @{displayName=System updates on virtual machine scale sets should be installed; description=Enable or disable virtual machine scale sets reporting of system updates}
allowedValues : {AuditIfNotExists, Disabled}
defaultValue  : AuditIfNotExists

header        : vmssEndpointProtectionMonitoringEffect
type          : String
metadata      : @{displayName=Endpoint protection solution should be installed on virtual machine scale sets; description=Enable or disable virtual machine scale sets endpoint
                protection monitoring}
allowedValues : {AuditIfNotExists, Disabled}
defaultValue  : AuditIfNotExists

header        : vmssOsVulnerabilitiesMonitoringEffect
type          : String
metadata      : @{displayName=Vulnerabilities in security configuration on your virtual machine scale sets should be remediated; description=Enable or disable virtual machine scale
                sets OS vulnerabilities monitoring}
allowedValues : {AuditIfNotExists, Disabled}
defaultValue  : AuditIfNotExists
person js2010    schedule 06.02.2020
comment
Да было бы так. Первоначально я получаю объект как PSCustomObject. Затем мне нужно было бы преобразовать его в JSON, поместить на диск, прочитать содержимое оттуда и прочитать его обратно в PSObject. Вместо этого я хотел бы пропустить материал JSON и работать напрямую с PS. - person Kamsiinov; 07.02.2020