Цикл по свойствам внутри объекта PSObject в PowerShell (из json)

После открытия файла .json в PowerShell у меня появился новый объект PSObject с именем $ json_sitesandsnets. В конечном итоге я хочу пройти через каждый сайт (Орландо, Денвер), пройти через каждую из их подсетей и сделать что-нибудь. Первоначально мне нужно создать эти подсети для соответствующего сайта в Active Directory с помощью командлета New-ADReplicationSubnet. Я уже использовал это для создания единой подсети, но у меня есть гораздо больший список сайтов и подсетей, с которыми я буду работать. Этот пример представляет собой лишь небольшую урезанную версию, которую можно опубликовать здесь. Как только я выясню, как получить доступ к этим подсетям в объектах Value, я мог бы просто передать каждый список подсетей в New-ADReplicationSubnet. Но я действительно хочу иметь возможность перебирать каждую подсеть для других целей. Я думаю, что это, наверное, несложно сделать, если вы знаете, как это делать.

Вот необработанный json:

{
"Orlando":  [
                        "10.10.10.0/24",
                        "10.10.20.0/24",
                        "10.10.30.0/24",
                        "10.10.40.0/24"
                    ],
"Denver":  [
                       "10.0.70.0/24",
                       "10.0.80.0/24",
                       "10.0.90.0/24",
                       "10.0.100.0/24",
                       "10.0.110.0/24",
                       "10.0.120.0/24"
                   ]
}

И я получаю такие свойства PSObject:

$ json_sitesandsnets.psobject.properties

Свойства PSObject

Когда я запускаю Debug в VSCode, я вижу объект PSObject и список (массив) подсетей: видя это в отладке

Вот код, который без проблем получает имя (Write-Host $ site.Name). Как видите, я пробовал несколько разных способов доступа к этим подсетям, которые являются Ценностью каждого сайта. И я просто не могу этого понять. Я прочитал так много статей и обсуждений на форумах о циклическом прохождении через PSObject, но, похоже, просто не могу найти золотого ответа на доступ и прохождение через массив, который является Value of the PSObject. Я чувствую, что я действительно близок.

foreach ($site in $json_sitesandsnets.PSObject.Properties) {
Write-Host $site.Name
$site| get-member -type NoteProperty | foreach-object {
    $subnet = $site."$($_.Value)"
    Write-Host $subnet
    Write-Host $_.Value
}
}

person stackDram    schedule 28.12.2019    source источник
comment
Что произойдет, если вы сделаете (внутри цикла) $ site.Value | гм   -  person Walter Mitty    schedule 29.12.2019
comment
$ site.value определенно то, что мне нужно.   -  person stackDram    schedule 29.12.2019
comment
Мне лень настраивать твой чехол на свой компьютер. Но я ожидаю, что $ site.value - это своего рода контейнер со списком, массивом или чем-то, состоящим из IP-адресов. Затем вам нужно будет написать внутренний цикл, чтобы брать их по одному и форматировать.   -  person Walter Mitty    schedule 29.12.2019


Ответы (3)


Мне кажется, что вы хотите вот этого.

foreach ($site in $json_sitesandsnets.PSObject.Properties) {
    Write-Host $site.Name -ForegroundColor Cyan
    $site.Value | Out-String | Write-Host 
}

Вывод

Результат # 1

Для значений подсети свойствами not являются Орландо и Денвер. Вы правильно поняли эту часть, но вашей строки $site| get-member там быть не должно. Вместо этого вы можете получить доступ к значению напрямую через $site.value. Если вам нужно сделать что-то еще, вы можете просмотреть эти значения в цикле, например:

$index = 0
Foreach ($subnet in $site.Value) {
    Write-Host "$($index): $subnet"
    $index+=1
}

Вывод

Результат # 2

person Sage Pourpre    schedule 28.12.2019
comment
Я верю, что это будет то, что мне нужно. После того, как я опубликовал это вчера, я просматривал его, и мне пришло в голову, что Site.Value должен предоставить мне эти подсети. Потом я увидел ваш пост, и он подтвердился. - person stackDram; 29.12.2019
comment
Вы можете помочь мне понять, зачем нам нужна индексация? .Value (подсети) уже выглядит как массив (см. Снимок экрана отладки). Мне удалось перебрать эти подсети следующим образом: foreach ($ site в $ json_sitesandsnets.PSObject.Properties) {Write-Host $ site.Name -ForegroundColor Голубой foreach ($ subnet в $ site.Value) {Write-Host $ subnet }} - person stackDram; 29.12.2019
comment
@stackDram Вам совершенно не нужно ничего индексировать. Этот бит должен был просто продемонстрировать базовый цикл, повторяющий все синусы подсети в моем основном примере, я обошел Foreach, используя $site.Value | Out-String | Write-Host - person Sage Pourpre; 29.12.2019

Вы можете сделать это, используя имя сайта для индексации. $json_sitesandsnets.($site.Name)

Я бы также использовал $json_sitesandsnets.PSObject.Properties.Name в foreach вместо $json_sitesandsnets.PSObject.Properties, чтобы упростить:

foreach ($site in $json_sitesandsnets.PSObject.Properties.Name) {
    Write-Host $site
    foreach ($subnet in $json_sitesandsnets.$site){
        Write-Host "logic for subnet $subnet"
    }
    # alternatively
    $json_sitesandsnets.$site | ForEach-Object {
        Write-Host "logic for subnet $_ (foreach-object)"
    }
}

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

# This tells you it's an array of "objects" with properties Length, Rank etc
Get-Member -InputObject $json_sitesandsnets.Denver

# This pipes the array elements, telling you they are strings with Length property
# In powershell strings are an object that only have properties Chars/Length
$json_sitesandsnets.Denver | Get-Member

# To only return the types
$json_sitesandsnets.Denver.GetType()
$json_sitesandsnets.Denver[0].GetType()
person G42    schedule 28.12.2019
comment
спасибо за ввод, я ценю эти дополнительные команды, которые помогают мне лучше понять объекты. - person stackDram; 29.12.2019

Я не думаю, что json может быть таким? С результирующим массивом объектов в PowerShell будет проще работать. Это может быть почти CSV.

[
  {
    "site": "Orlando",
    "subnets": [
      "10.10.10.0/24",
      "10.10.20.0/24",
      "10.10.30.0/24",
      "10.10.40.0/24"
    ]
  },
  {
    "site": "Denver",
    "subnets": [
      "10.0.70.0/24",
      "10.0.80.0/24",
      "10.0.90.0/24",
      "10.0.100.0/24"
    ]
  }
]


cat sites.json | convertfrom-json     

site    subnets
----    -------
Orlando {10.10.10.0/24, 10.10.20.0/24, 10.10.30.0/24, 10.10.40.0/24}
Denver  {10.0.70.0/24, 10.0.80.0/24, 10.0.90.0/24, 10.0.100.0/24}
person js2010    schedule 28.12.2019
comment
это действительно интересно ... Мне нравится структура, и при необходимости я могу это сделать. - person stackDram; 29.12.2019