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