Working with JSON
Learn how to parse, create, and manipulate JSON data in PowerShell using ConvertFrom-Json and ConvertTo-Json.
Overview
JSON (JavaScript Object Notation) is a lightweight data format commonly used for APIs, configuration files, and data exchange. PowerShell makes it easy to convert between JSON strings and PowerShell objects, allowing you to work with JSON data naturally.
Common use cases:
- API request and response handling
- Configuration file management
- Data serialization and storage
- Cross-platform data exchange
- Web service integration
Basic Syntax
Converting JSON to PowerShell (ConvertFrom-Json)
Convert JSON strings into PowerShell objects:
# Simple JSON string
$json = '{"name":"Raymond","age":30,"active":true}'
$user = $json | ConvertFrom-Json
# Access properties with dot notation
$user.name # "Raymond"
$user.age # 30
$user.active # True
Converting PowerShell to JSON (ConvertTo-Json)
Convert PowerShell objects into JSON strings:
# Create a hashtable
$config = @{
Server = "db01.company.com"
Port = 5432
Timeout = 30
EnableSSL = $true
}
# Convert to JSON
$json = $config | ConvertTo-Json
# Result:
# {
# "Server": "db01.company.com",
# "Port": 5432,
# "Timeout": 30,
# "EnableSSL": true
# }
Working with Nested JSON
Handle complex JSON structures:
# Nested JSON example
$json = @"
{
"user": {
"name": "Raymond",
"contact": {
"email": "raymond@example.com",
"phone": "555-1234"
}
},
"status": "active"
}
"@
$data = $json | ConvertFrom-Json
# Access nested properties
$data.user.name # "Raymond"
$data.user.contact.email # "raymond@example.com"
$data.user.contact.phone # "555-1234"
$data.status # "active"
Working with JSON Arrays
Work with arrays in JSON:
# JSON with array
$json = @"
{
"users": [
{"name": "Alice", "age": 28},
{"name": "Bob", "age": 32},
{"name": "Charlie", "age": 25}
]
}
"@
$data = $json | ConvertFrom-Json
# Access array elements
$data.users[0].name # "Alice"
$data.users[1].age # 32
$data.users.Count # 3
# Loop through array
foreach ($user in $data.users) {
Write-Output "$($user.name) is $($user.age) years old"
}
# Filter array
$data.users | Where-Object {$_.age -gt 30}
The -Depth Parameter
Control how deeply nested objects are converted:
# Complex nested object
$config = @{
Level1 = @{
Level2 = @{
Level3 = @{
Level4 = "Deep value"
}
}
}
}
# Default depth is 2 - deeper levels become strings
$json = $config | ConvertTo-Json
# Level3 and beyond will be truncated!
# Increase depth for deeply nested objects
$json = $config | ConvertTo-Json -Depth 5
# When reading JSON, increase depth if needed
$data = $json | ConvertFrom-Json -Depth 10
Pretty-Printing JSON
Format JSON for readability:
# Default behavior: Pretty-printed (indented)
$data = @{Name="Raymond"; City="St. Louis"; Active=$true}
$data | ConvertTo-Json
# Output (formatted with indentation):
# {
# "Name": "Raymond",
# "City": "St. Louis",
# "Active": true
# }
# Compact JSON (single line) - Use -Compress parameter
$compact = $data | ConvertTo-Json -Compress
# Output: {"Name":"Raymond","City":"St. Louis","Active":true}
# Note: ConvertTo-Json pretty-prints by default
# Use -Compress when you need single-line output (for APIs, storage, etc.)
Reading and Writing JSON Files
Work with JSON files:
# Read JSON from file
$config = Get-Content -Path C:\Config\settings.json -Raw | ConvertFrom-Json
# Access properties
$config.Database.Server
$config.Database.Port
# Modify and save back
$config.Database.Port = 5433
$config | ConvertTo-Json -Depth 10 | Set-Content -Path C:\Config\settings.json
# Create new JSON file
$settings = @{
AppName = "MyApp"
Version = "1.0.0"
Settings = @{
Theme = "Dark"
Language = "en-US"
}
}
$settings | ConvertTo-Json | Out-File -FilePath C:\Config\app.json
Important Parameters
| Parameter | Cmdlet | Description | Example |
|---|---|---|---|
-Depth | ConvertTo-Json | Maximum nesting levels to convert (default: 2) | -Depth 5 |
-Compress | ConvertTo-Json | Output as single-line JSON | -Compress |
-AsHashtable | ConvertFrom-Json | Return hashtable instead of PSCustomObject (PS 6+) | -AsHashtable |
-Depth | ConvertFrom-Json | Maximum nesting levels to parse (default: 1024) | -Depth 10 |
-NoEnumerate | ConvertFrom-Json | Don't enumerate arrays with single element | -NoEnumerate |
Common JSON Patterns
# Pattern 1: API response handling
$response = Invoke-RestMethod -Uri "https://api.example.com/users/1"
Write-Output "User: $($response.name), Email: $($response.email)"
# Pattern 2: Configuration file
$config = Get-Content C:\app-config.json -Raw | ConvertFrom-Json
$dbConnection = "Server=$($config.db.server);Port=$($config.db.port)"
# Pattern 3: Building API request body
$payload = @{
username = "jdoe"
email = "jdoe@example.com"
active = $true
} | ConvertTo-Json
Invoke-RestMethod -Uri "https://api.example.com/users" -Method Post -Body $payload -ContentType "application/json"
# Pattern 4: Array of objects to JSON
$servers = @(
@{Name="Server01"; IP="192.168.1.10"; Role="Web"}
@{Name="Server02"; IP="192.168.1.11"; Role="Database"}
)
$servers | ConvertTo-Json
Common Use Cases
Use Case 1: Parse API Response
What it does: Convert JSON from web APIs into PowerShell objects for data extraction
# Fetch and parse API response
$response = Invoke-RestMethod -Uri "https://api.github.com/users/octocat"
Write-Output "User: $($response.name), Location: $($response.location)"
Write-Output "Followers: $($response.followers), Repos: $($response.public_repos)"
Use Case 2: Save Configuration Files
What it does: Store application settings in JSON format for easy editing and portability
# Create configuration object
$config = @{
Database = @{
Server = "db01.local"
Port = 5432
Timeout = 30
}
Logging = @{
Level = "Info"
Path = "C:\Logs\app.log"
}
}
# Save to JSON file
$config | ConvertTo-Json -Depth 5 | Out-File "C:\Config\appsettings.json"
Use Case 3: Build API Request Bodies
What it does: Create JSON payloads for POST/PUT requests to REST APIs
# Build request body
$newUser = @{
firstName = "John"
lastName = "Doe"
email = "john.doe@example.com"
department = "IT"
active = $true
}
# Convert and send to API
$jsonBody = $newUser | ConvertTo-Json
Invoke-RestMethod -Uri "https://api.example.com/users" -Method Post -Body $jsonBody -ContentType "application/json"
Use Case 4: Data Exchange Between Systems
What it does: Serialize PowerShell data for cross-platform compatibility and storage
# Export system inventory to JSON
$inventory = Get-CimInstance Win32_ComputerSystem | Select-Object Name, Manufacturer, Model, TotalPhysicalMemory
$inventory | ConvertTo-Json | Out-File "C:\Reports\inventory.json"
# Import on another system
$importedData = Get-Content "C:\Reports\inventory.json" -Raw | ConvertFrom-Json
Write-Output "Computer: $($importedData.Name), RAM: $($importedData.TotalPhysicalMemory / 1GB)GB"
Use Case 5: Log Structured Data
What it does: Create machine-readable log entries in JSON format for analysis
# Create structured log entry
$logEntry = @{
Timestamp = (Get-Date).ToString("o")
Level = "Error"
Message = "Database connection failed"
Details = @{
Server = "db01.local"
Port = 5432
ErrorCode = "ConnectionTimeout"
}
}
# Append to log file
$logEntry | ConvertTo-Json -Compress | Add-Content "C:\Logs\app-structured.log"
Real-World Examples
Example: Parse API Response
Scenario: Fetch user data from a REST API and extract specific information
# Fetch JSON from API
$response = Invoke-RestMethod -Uri "https://api.github.com/users/octocat"
# Response is automatically converted from JSON
Write-Output "Username: $($response.login)"
Write-Output "Name: $($response.name)"
Write-Output "Public Repos: $($response.public_repos)"
Write-Output "Followers: $($response.followers)"
Example: Configuration Management
Scenario: Load application settings from JSON file
# settings.json content:
# {
# "database": {
# "server": "db01.local",
# "port": 5432,
# "database": "myapp"
# },
# "logging": {
# "level": "Info",
# "path": "C:\\Logs\\app.log"
# }
# }
# Load configuration
$config = Get-Content -Path .\settings.json -Raw | ConvertFrom-Json
# Use configuration values
$connectionString = "Server=$($config.database.server);Port=$($config.database.port);Database=$($config.database.database)"
$logPath = $config.logging.path
$logLevel = $config.logging.level
Write-Output "Connecting to: $connectionString"
Write-Output "Logging to: $logPath at level $logLevel"
Example: Create JSON for API POST Request
Scenario: Send new user data to an API
# Build user object as hashtable
$newUser = @{
firstName = "John"
lastName = "Doe"
email = "john.doe@example.com"
department = "IT"
active = $true
roles = @("user", "contributor")
}
# Convert to JSON
$jsonBody = $newUser | ConvertTo-Json
# Send to API
$response = Invoke-RestMethod -Uri "https://api.example.com/users" `
-Method Post `
-Body $jsonBody `
-ContentType "application/json"
Write-Output "User created with ID: $($response.id)"
Example: Process Array of JSON Objects
Scenario: Parse a JSON file containing multiple records
# employees.json:
# [
# {"name": "Alice", "dept": "IT", "salary": 75000},
# {"name": "Bob", "dept": "HR", "salary": 65000},
# {"name": "Charlie", "dept": "IT", "salary": 80000}
# ]
$employees = Get-Content .\employees.json -Raw | ConvertFrom-Json
# Filter IT employees
$itEmployees = $employees | Where-Object {$_.dept -eq "IT"}
# Calculate average IT salary
$avgSalary = ($itEmployees | Measure-Object -Property salary -Average).Average
Write-Output "IT Employees: $($itEmployees.Count)"
Write-Output "Average IT Salary: `$$avgSalary"
# Export to CSV
$itEmployees | Export-Csv -Path .\it-employees.csv -NoTypeInformation
Tips & Tricks
Always Use -Raw When Reading JSON Files
Access Properties with Bracket Notation for Special Characters
Test JSON Validity Before Converting
ConvertFrom-Json Creates PSCustomObjects, Not Hashtables
$json = '{"name":"Raymond","age":30}'
$obj = $json | ConvertFrom-Json
# This is a PSCustomObject, not a hashtable
$obj.GetType().Name # PSCustomObject
# Can't use hashtable syntax
# $obj["name"] # Won't work!
# Use dot notation instead
$obj.name # "Raymond" - Works!
# To convert to hashtable:
$hash = @{}
$obj.PSObject.Properties | ForEach-Object {
$hash[$_.Name] = $_.Value
}
Watch for Null Values in JSON
Deep Nesting Requires Increased -Depth
# Default depth is 2 - data beyond that gets stringified
$deep = @{
L1 = @{ L2 = @{ L3 = @{ L4 = "value" } } }
}
# BAD - L3 and beyond become "[Object]" string
$json = $deep | ConvertTo-Json
# GOOD - Increase depth
$json = $deep | ConvertTo-Json -Depth 5
$restored = $json | ConvertFrom-Json -Depth 5
$restored.L1.L2.L3.L4 # "value"
Related Topics
- API Interactions - REST API calls and JSON handling
- String Manipulation - Text processing and formatting
- Arrays & Collections - Hashtables and arrays
- Variables & Data Types - PowerShell data types
- One-Liners - Quick JSON conversion examples
Additional Resources
- Microsoft Docs: ConvertFrom-Json
- Microsoft Docs: ConvertTo-Json
- JSON.org - JSON specification and documentation
- JSONLint - JSON validator and formatter