如何将 Get-ADComputer PowerShell 结果输出为包含 IP 和父对象(例如:Windows 服务器)的 JSON 格式?

How to output Get-ADComputer PowerShell results to JSON format containing IP and a parent object (Eg: Windows Servers)?

我做了以下 ps1 脚本:

Import-Module ActiveDirectory
Get-ADComputer -Filter "OperatingSystem -Like '*Windows Server*' -and Enabled -eq 'True'" | Select-Object Name, DNSHostName | ConvertTo-Json | Out-File "C:\adServers.json"

输出为:

[
    {
        "Name":  "exampleServer1",
        "DNSHostName":  "exampleServer1.domain.com"
    },
    {
        "Name":  "exampleServer2",
        "DNSHostName":  "exampleServer2.domain.com"
    } ]

它生成一个列表,其中包含描述为“Windows 服务器”的所有对象。 但我想要实现的是:

I will do more of this, but instead of Windows Servers i will also include lists with Linux Servers, and some other devices.

I also need that one object contains the value IP Address. (Name, DNSHostName, IP Address)

Since i will gather multiple devices with different descriptions, i need a title for each list i generate. Below a example for easier understanding...

这是我想要实现的,输出将采用以下 JSON 格式:

{
    "Linux Servers": [{
            "Name": "exampleServer3",
            "DNSHostName": "exampleServer3.domain.com",
            "IP": "192.168.1.3"
        },
        {
            "Name": "exampleServer3",
            "DNSHostName": "exampleServer3.domain.com",
            "IP": "192.168.1.3"
        }
    ],
    "Windows Servers": [{
            "Name": "exampleServer1",
            "DNSHostName": "exampleServer1.domain.com",
            "IP": "192.168.1.1"
        },
        {
            "Name": "exampleServer2",
            "DNSHostName": "exampleServer2.domain.com",
            "IP": "192.168.1.2"
        }
    ]
}

有谁知道我该如何改进我的代码才能做到这一点? 我正在研究这个,因为我将把它用作 Zabbix 监控软件的发现规则。

我真的不知道如何或从哪里开始。 任何提示或建议真的很感激...

PS:我会用我想出的代码和我做的所有测试不断更新这个答案。

提前致谢...

编辑:

我能够通过使用 mklement0' 和 Mathias 对使用 Group-Object 对对象进行分组的出色解释来解决这个问题。

最终结果:

Import-Module ActiveDirectory
$listaServidores = [ordered] @{}

# Raw command:
# Get-ADComputer -Filter "(OperatingSystem -Like '*' -and Enabled -eq 'True')" -Property OperatingSystem, IPv4Address | 
# Select-Object Name, DNSHostName, IPv4Address, OperatingSystem |

# Exportar para JSON: ConvertTo-Json | Set-Content -Encoding Utf8 "C:\adServers.json"
Get-ADComputer -Filter "(OperatingSystem -Like '*Windows Server*' -and Enabled -eq 'True')" -Property OperatingSystem, IPv4Address | 
Select-Object Name, DNSHostName, IPv4Address, OperatingSystem |
Group-Object {
    switch -Wildcard ($_.OperatingSystem) {
        '*Windows Server*'  { 'Windows Servers' }
        '*Windows 7*'   { 'Outdated Computers' } # I will use this later. Outdated users, need to update to Windows 10
        Default             { 'Others' } # Other devices Discovery Rules. Will dig around later
    }
} | 
ForEach-Object {
    $listaServidores[$_.Name] = 
        @($_.Group | Select-Object Name, DNSHostName, @{ Name='IP'; Expression='IPv4Address'})
}

$listaServidores | ConvertTo-Json -Depth 3 # !! -Depth is needed to avoid truncation
    # Set-Content -Encoding Utf8 "C:\adServers.json"

您可以使用 Group-Object cmdlet to group computers by their .OperatingSystem property, which allows you to construct an ordered hashtable[1] that translates into the desired JSON structure when passed to ConvertTo-Json:

Import-Module ActiveDirectory

# Initialize an ordered hashtable that will collect the groups.
$orderedHash = [ordered] @{}

Get-ADComputer -Filter "Enabled -eq 'True'" -Property DNSHostName, IPv4Address, OperatingSystem | 
  Group-Object OperatingSystem | # See below re higher-level grouping.
  ForEach-Object {
    # Add an entry named for the current group (OS)
    # with the array of the group's members as the value.
    $orderedHash[$_.Name] = 
      @($_.Group | Select-Object Name, DNSHostName, @{ Name='IP'; Expression='IPv4Address'})
  }

# Convert to JSON and save to a file.
$orderedHash | 
  ConvertTo-Json -Depth 3 | # !! -Depth is needed to avoid truncation
    Set-Content -Encoding Utf8 C:\adServers.json

显示如何根据单独过滤的 Get-ADComputer 调用 显式 创建组,这允许任意 higher-level 分组,如以及仅对感兴趣的计算机进行处理。

如果需要处理所有(已启用)计算机,您可以通过对上述内容进行调整来实现higher-level分组也是解决方案,通过传递执行映射的 脚本块 ({ ... }) 作为(位置隐含的)-Property 参数。

例如,您可以使用以下内容代替 Group-Object OperatingSystem

Group-Object {
  switch -Wildcard ($_.OperatingSystem) {
    '*Windows*' { 'Windows Servers' }
    '*Linux*'   { 'Linux Servers' }
    Default     { 'Others' } 
  }
}

[1] ordered 哈希表 ([ordered] @{ ... }) - 与常规哈希表 (@{ ... }) 不同 - 保留其条目的定义顺序。
[ordered] 是唯一受支持的限定符,虽然它看起来像是对(不存在的)[ordered] 类型的转换,但事实并非如此;相反,它是语法糖,可以转换为 System.Collections.Specialized.OrderedDictionary instance (vs. System.Collections.Hashtable 用于常规哈希表)。
请参阅概念性 about_Hash_Tables 帮助主题。

向您展示如何按 OperatingSystem 属性 自动对计算机进行分组,并根据这些 JSON 构造结果。

但是,如果您希望每个组有一个不同的标签,或者您希望其中的一些分组在一起呢?

如果您知道要如何预先标记它们,则可以将每个组组织到一个哈希表中,并关联您要为每个组使用的查询过滤器:

$OSGroups = @{
  'LinuxServers' = "OperatingSystem -Like '*Windows Server*' -and Enabled -eq 'True'"
  'WindowsServers' = "OperatingSystem -Like '*Windows Server*' -and Enabled -eq 'True'"
}

现在我们只需要使用这些条目中的每一个来获取相关计算机并将它们添加到以输出对象上的键(例如 WindowsServers)命名的 属性 中:

# prepare another hashtable to hold all the information
$outputData = [ordered]@{}

# loop throw the different groups of computers you want to report on
foreach($kvp in $OSGroups.GetEnumerator())
{
  $groupName = $kvp.Key
  $groupFilter = $kvp.Value

  # Assign the output for the given filter to the appropriate entry in our output dictionary
  $outputData[$kvp.Key] = Get-ADComputer -Filter $kvp.Value -and Enabled -eq 'True'" | Select-Object Name, DNSHostName
}

# this will now produce the desired output format
$outputData |ConvertTo-Json -Depth 3 |Set-Content path\to\out.json