Home > Net >  How to output Get-ADComputer PowerShell results to JSON format containing IP and a parent object (Eg
How to output Get-ADComputer PowerShell results to JSON format containing IP and a parent object (Eg

Time:03-09

I did the following ps1 script:

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"

The output is:

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

It generates a list with all the objects that are described as "Windows Servers". But what i want to achieve is:

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...

Here's what i want to achieve, the output would be on the following JSON format:

{
    "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"
        }
    ]
}

Does anyone knows how can i improve my code in order to do that? I'm working on this because i will use it as a Discovery Rule for Zabbix Monitoring Software.

I don't really know on how or where to start. Any tips or suggestion is really appreciate it...

PS: I will keep updating this answer with the codes i come up with, and all the tests i do.

Thanks in advance...

CodePudding user response:

You can use the Group-Object cmdlet to group computers by their .OperatingSystem property, which allows you to construct an ordered hashtable that translates to the desired JSON structure:

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

Mathias' helpful answer shows how to create groups explicitly, based on individually filtered Get-ADComputer calls, which allows arbitrary, higher-level groupings, as well as limiting processing to only computers of interest.

If processing all (enabled) computers is desired, you can achieve higher-level grouping with a tweak to the above solution too, by passing a script block ({ ... }) that performs the mapping as the (positionally implied) -Property argument.

E.g., instead of Group-Object OperatingSystem, you could to the following:

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

CodePudding user response:

mklement0's excellent answer shows you how to automatically group the computers by the OperatingSystem property and construct the resulting JSON based on those.

But what if you want a different label for each group, or you want some of them grouped together?

If you know how you want to label them up front, you can organize each group into a hashtable and associate the query filter you want to use for each:

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

Now we just need to use each of those entries to fetch the relevant computers and add them to a property named for the key (eg. WindowsServers) on an output object:

# 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
  • Related