PowerShell & JSON: A Practical Primer
JSON has become the universal language of data exchange — and PowerShell handles it surprisingly well. Whether you’re parsing API responses, transforming configuration files, or extracting subsets of records, PowerShell’s built-in “cmdlets” get the job done without having to rely on third-party tools. One of the biggest strong suits, in my opinion, of using an Object-Oriented shell scripting language like PowerShell, is the versatility to transform and query sets of data on the fly. A lot of opponents to PowerShell target this object-oriented design as bloated or uneccessary, but I disagree.
In PowerShell, an object is a structured piece of data that bundles together two things:
- Properties — the data it holds (e.g., a file object has .Name, .Size, .LastWriteTime)
- Methods — actions it can perform (e.g., a string object has .ToUpper(), .Replace())
This comes from .NET, which PowerShell is built on. Almost everything in PowerShell is an object — strings, numbers, files, processes, JSON records, command output — rather than plain text like in traditional shells such as BASH, ZSH etc.
The practical upside is that you can “dot” into properties directly instead of some complicated mechanism to parse and extract textual data yourself. here’s a quick example:
# Example of getting file properties
$file = Get-Item ".\data.json"
$file.Name # "data.json"
$file.Length # 4096 (bytes, as a number you can compare/sort)
In the context of this article, when you run ConvertFrom-Json, PowerShell turns your JSON into a PSCustomObject — an object whose properties map directly to your JSON keys. That’s why you can write $_.address.city to drill into nested fields, rather than doing any string parsing yourself.
Loading JSON
Loading JSON into a local shell variable is extremely easy. Most of the work I do, relies on quick iterations against a set of data to work out a more cohesive solution to parse and cherry-pick the data I need for the given problem.
Loading Data from a File
Use Get-Content to read the file and pipe it into ConvertFrom-Json:
$data = Get-Content -Path ".\users.json" -Raw | ConvertFrom-Json
The
-Rawflag reads the entire file as a single string rather than line-by-line — this is essential for valid JSON parsing.
Loading Data from an API or Web Request
Invoke-RestMethod automatically deserializes JSON responses for you:
$response = Invoke-RestMethod -Uri "https://jsonplaceholder.typicode.com/users"
Inspecting the Structure
Once loaded, explore the object like any other:
$data | Get-Member # Show properties and methods
$data | Select-Object -First 3 # Preview the first 3 records
$data.Count # Total number of items
Searching and Filtering
Probably one of the most powerful features of PowerShell, is the ability chain cmdlets together to both select and iterate over large sets of data. I often use PowerShell over a Python repl to map out data, since PowerShell lets you quickly iterate over list like structures, to get subvalues, much more intuitively. In larger, more complicated, JSON files that could change their structure based on the dataset, this becomes invaluable.
Simple Property Match
Use Where-Object to filter records:
# Find all users in a specific city
$data | Where-Object { $_.address.city -eq "Portland" }
# Find users whose name starts with "J"
$data | Where-Object { $_.name -like "J*" }
The $_ in the above script, could also be written as $PSItem and simply represents the current item being iterated over.
Numeric Comparisons
# Orders over $500
$orders | Where-Object { $_.total -gt 500 }
# Items with low stock
$inventory | Where-Object { $_.quantity -le 10 }
Multiple Conditions
$data | Where-Object { $_.status -eq "active" -and $_.role -eq "admin" }
Selecting and Reshaping Fields
Use Select-Object to pick only the fields you need:
$data | Select-Object name, email, @{Name="City"; Expression={$_.address.city}}
The @{Name=...; Expression={...}} syntax lets you rename or compute fields on the fly — handy for flattening nested structures.
Exporting Subsets
Most often, you will probably want to extract and save subsets of data you are inspecting. In these cases, it is easy to select, extract, and reshape / massage your data into a format that you can then hand off to an export function of some kind. This could be for automated reporting processes or any other one off scripts you are using to inspect target processes.
Export to CSV
Once you have a filtered, shaped result, Export-Csv writes it out cleanly:
$data |
Where-Object { $_.status -eq "active" } |
Select-Object id, name, email |
Export-Csv -Path ".\active_users.csv" -NoTypeInformation
-NoTypeInformationsuppresses the#TYPEheader line that PowerShell adds by default — you almost always want this.
Export Back to JSON
To write a filtered subset back out as JSON:
$data |
Where-Object { $_.role -eq "admin" } |
ConvertTo-Json -Depth 5 |
Out-File -FilePath ".\admins.json"
The
-Depthparameter controls how many levels of nested objects are serialized. The default is2, which silently truncates deeper structures — set it higher when working with complex JSON.
Export to a Table in the Console
For quick inspection without writing a file:
$data | Where-Object { $_.active -eq $true } | Format-Table -AutoSize
Modifying JSON Data
You can update properties in memory and re-export:
# Add a new field to every record
$data | ForEach-Object { $_ | Add-Member -NotePropertyName "exported_at" -NotePropertyValue (Get-Date -Format "o") -Force }
# Update a specific record
($data | Where-Object { $_.id -eq 42 }).status = "inactive"
# Save the modified data
$data | ConvertTo-Json -Depth 5 | Out-File ".\updated_data.json"
Putting It All Together
Here’s a complete workflow: load a JSON file, filter it, reshape it, and export two formats:
# 1. Load
$users = Get-Content ".\users.json" -Raw | ConvertFrom-Json
# 2. Filter and shape
$subset = $users |
Where-Object { $_.active -eq $true -and $_.role -ne "guest" } |
Select-Object id, name, email, role,
@{Name="City"; Expression={$_.address.city}}
# 3. Export to CSV
$subset | Export-Csv ".\active_non_guests.csv" -NoTypeInformation
# 4. Export to JSON
$subset | ConvertTo-Json -Depth 3 | Out-File ".\active_non_guests.json"
Write-Host "Done. $($subset.Count) records exported."
Quick Reference
Below is quick reference of some of the concepts we explored together in this article.
| Task | Cmdlet |
|---|---|
| Load JSON from file | Get-Content -Raw | ConvertFrom-Json |
| Load JSON from URL | Invoke-RestMethod |
| Filter records | Where-Object { $_.prop -eq "value" } |
| Pick fields / rename | Select-Object with computed properties |
| Export to CSV | Export-Csv -NoTypeInformation |
| Export to JSON | ConvertTo-Json -Depth N | Out-File |
| Modify in-place | ForEach-Object + Add-Member or direct assignment |
Bottom Line
PowerShell’s pipeline model makes JSON workflows feel natural — each step flows cleanly into the next. Once you’re comfortable with ConvertFrom-Json, Where-Object, and Select-Object — you have everything you need to slice and reshape almost any JSON dataset.