Creating and Parsing Complex JSON Files in PowerShell
Happy New Year and welcome back Shackers!
This week, we’re deep diving into complex JSON; the basis of almost all API interactions. Back in September (Week 3), we covered the origins of JSON and how to work with simple JSON structures in PowerShell. This week we’ll look at creating nested complex JSON files, exporting them, and parsing them back into PowerShell objects.
Creating Complex JSON Structures
Let’s start by building our own JSON masterpiece! In PowerShell you can use hashtables and custom objects to nest data as deep as you’d like. Arrays let you group things together; think lists of skills or projects.
Example: Building a multi-level JSON object
$person = [PSCustomObject]@{
Name = "Alex Scriptshack"
Age = 32
Contact = [PSCustomObject]@{
Email = "alex@scriptshack.com"
Phone = "555-1234"
}
Skills = @("PowerShell", "JSON", "Markdown")
Projects = @(
[PSCustomObject]@{
Name = "Lesson Planner"
Year = 2025
},
[PSCustomObject]@{
Name = "API Explorer"
Year = 2026
}
)
}
In our first semester we learned how to build Custom PowerShell Objects using PSCustomObject and hashtables. Here, we’re using those same techniques to create a nested structure that represents a person with contact info, skills, and projects. Let’s convertto-json to see how it looks as JSON:
$person | ConvertTo-Json -Depth 4
{
"Name": "Alex Scriptshack",
"Age": 32,
"Contact": {
"Email": "alex@scriptshack.com",
"Phone": "555-1234"
},
"Skills": [
"PowerShell",
"JSON",
"Markdown"
],
"Projects": [
{
"Name": "Lesson Planner",
"Year": 2025
},
{
"Name": "API Explorer",
"Year": 2026
}
]
}
In week 3 we learned the syntax of JSON and how to build arrays, properties, and sub-objects. Here we can see the pscustomobjects have been converted to brackets, while the hashtable pairs are within braces. The -Depth parameter is crucial when dealing with nested objects. Without it, PowerShell will truncate the output. Depth needs to be set to the maximum level of nesting in your object.
The syntax of JSON is straightforward:
Objects are enclosed in curly braces
{}and contain key-value pairs.Arrays are enclosed in square brackets
[]and contain ordered lists of items.Key-Value Pairs are written as
"key": value, where the key is a string and the value can be a string, number, object, array, boolean, or null. Keys and values are separated by a colon:and pairs are separated by commas,. Key names must be unique within an object, and enclosed in double quotes.
Exporting JSON
With this object created, we can convert it to JSON easily using ConvertTo-Json. To save it to a file, we can use Out-File or Set-Content. But we are here to look at some truly complex JSON structures. Let’s use Get-Service -Name DHCP to create a more complex object representing a service, then export that to JSON.
$service = Get-Service -Name DHCP
# The service object has multiple nested properties of the dependency services (which there are many for DHCP). Changing the depth parameter when converting increases the size of the output substantially.
$serviceJson2 = $service | ConvertTo-Json -Depth 2
$ServiceJSON2.Length # Outputs the length of the JSON string nested to depth 2
# Example - "10335"
$serviceJson5 = $service | ConvertTo-Json -Depth 5
$ServiceJSON5.Length # Outputs the length of the JSON string nested to depth 5
# Example - "252005"
$serviceJson10 = $service | ConvertTo-Json -Depth 10
$ServiceJSON10.Length # The output length at depth 10 is much, much larger!
# Example - "74849800"
Not only will increasing the depth give you more information, but it will also increase the size of your JSON file significantly and take more time to convert. Be cautious when exporting very deep objects, as they can impact script and API performance, and may contain far more information than needed.
Save $ServiceJson2 to a file called service2.json, and $ServiceJson5 to service5.json for comparison:
$ServiceJson2 | Out-File -FilePath "service2.json"
$ServiceJson5 | Out-File -FilePath "service5.json"
If you open these files in a text editor, you can see the difference in size and detail. The service5.json file contains thousands of lines of nested information about the service dependencies and configurations. Can you spot the arrays, hashtables, and nested objects in the JSON structure?
Parsing Complex JSON
Now we will import the service5.json file back into PowerShell and explore how to access the nested properties.
$JsonService5 = Get-Content -Path "service5.json" | ConvertFrom-Json
$JsonService5 | Format-List *
$JsonService5.DependentServices # Accessing the array of dependent services
$JsonService5.DependentServices[0] # Accessing the first dependent service object
$JsonService5.DependentServices[0].ServicesDependedOn[0] # Accessing a nested property within the first dependent service
$JsonService5.DependentServices[0].ServicesDependedOn[0].ServicesDependedOn # Accessing even deeper nested properties
You can export or convert any of these nested hashtables or arrays back to JSON as needed. For example, to export just the dependent services as JSON:
$DependentServicesJSON = $JsonService5.DependentServices | ConvertTo-Json -Depth 5
$DependentServicesJSON | Out-File -FilePath "dependentServices.json"
Adding or removing properties using PowerShell
When working with complex JSON structures, you may need to add or remove properties from the objects. You can do this easily in PowerShell by manipulating the properties of the objects before converting them back to JSON. Let’s go back to the custom object we created at the beginning of the lesson:
# Create the $person array again
$person = [PSCustomObject]@{
Name = "Alex Scriptshack"
Age = 32
Contact = [PSCustomObject]@{
Email = "alex@scriptshack.com"
Phone = "555-1234"
}
Skills = @("PowerShell", "JSON", "Markdown")
Projects = @(
[PSCustomObject]@{
Name = "Lesson Planner"
Year = 2025
},
[PSCustomObject]@{
Name = "API Explorer"
Year = 2026
}
)
}
# Create the new Address hashtable
$Address = [PSCustomObject]@{
Street = "123 Scriptshack Lane"
City = "Codeville"
State = "CA"
Zip = "90210"
}
# Add the Address property to the existing Person object
$Person | Add-Member -MemberType NoteProperty -Name Address -Value $Address
$Person | Format-ListTo remove a property, you can use the ‘.Remove()’ method on the PSObject.Properties collection of the object.
# Using the Remove method to delete the Address property
$Person.PSObject.Properties.Remove("Address")
$Person | Format-List
# Alternatively, you can use 'Select-Object' to create a new object without the unwanted property
$Person = $Person | Select-Object Name, Age, Contact, Skills, Projects
$Person | Format-List
# Now let's fix the $person variable by putting the address back in
$Person | Add-Member -MemberType NoteProperty -Name Address -Value $Address
$Person | Format-List
Now, if we convert $Person to JSON again, it will include the new Address property:
$jsonPerson = $Person | ConvertTo-Json -Depth 2
$jsonPerson | Out-File -FilePath "person_with_address.json"
Output:
{
"Name": "Alex Scriptshack",
"Age": 32,
"Contact": {
"Email": "alex@scriptshack.com",
"Phone": "555-1234"
},
"Skills": [
"PowerShell",
"JSON",
"Markdown"
],
"Projects": [
{
"Name": "Lesson Planner",
"Year": 2025
},
{
"Name": "API Explorer",
"Year": 2026
}
],
"Address": {
"Street": "123 Scriptshack Lane",
"City": "Codeville",
"State": "CA",
"Zip": "90210"
}
}
If working with JSON text files you intend to import, you can add or remove properties manually through a text editor.
To remove the new Address hashtable from the Person JSON, simply delete that section from the JSON file in your text editor before importing it back into PowerShell.
Remember to remove any trailing commas when deleting properties in JSON text files, as this will cause errors when importing.
Common Pitfalls
Watch out for these classic JSON gotchas:
Depth limits: PowerShell’s default depth is 2. If your object is deeper, set
-Depthhigher or you’ll lose data! Setting depth too high can create massive JSON files and will slow down your scripts.Arrays vs Objects: Use
[]for arrays, and@{}for objects. Mixing them up can cause headaches.Type mismatches: During conversions, ensure the data types match what your API expects (e.g., strings vs numbers).
Trailing commas: JSON does not allow trailing commas after the last item in an object or array. Always double-check your JSON syntax.
Practical Demo
Let’s put it all together! Here’s your JSON challenge:
Build a nested object
Export to JSON and save to file
Edit the JSON file - Add a new property, and a new nested object
Import the JSON file back into PowerShell
Verify the new property exists using dot notation
Remove the new nested object from the PowerShell object
Export the modified object back to JSON and save to a new file
Check the export JSON files to see the differences before and after modification.
Homework
Ready for a challenge? Create a JSON file that represents a team. Include members, their roles, and contact info. Then, write a PowerShell script to parse the file and print out each member’s email address.

