Escape JSON for PowerShell and Power Automate — Practical Patterns
- Build a hashtable and pipe to ConvertTo-Json — PowerShell handles escaping for you.
- For Power Automate, use the json() function to parse strings; concat() carefully when building.
- Single quotes wrap literal strings in PowerShell; double quotes interpolate.
Table of Contents
The Microsoft stack has its own JSON quirks. PowerShell prefers hashtables converted to JSON over hand-written strings; Power Automate has its own expression language for handling escape sequences in flow steps. Both work well once you stop fighting them with shell-style quoting.
PowerShell — Build the Object, Don't Escape the JSON
The PowerShell idiom is to build a hashtable in PowerShell and convert it to JSON at the end:
$body = @{
name = "Alex"
email = "[email protected]"
quote = 'She said "hi"'
} | ConvertTo-Json
Invoke-RestMethod -Uri "https://api.example.com/users" -Method POST -ContentType "application/json" -Body $body
ConvertTo-Json handles all the escape rules. Quotes inside string values get escaped. Special characters get unicode escapes. You never write a backslash by hand.
For nested objects, nested hashtables work the same way:
$body = @{
user = @{
name = "Alex"
roles = @("admin", "editor")
}
settings = @{
notifications = $true
}
} | ConvertTo-Json -Depth 5
The -Depth parameter is important. PowerShell defaults to 2 levels of depth, which silently truncates deeper nesting. For anything beyond a flat object, set -Depth explicitly.
When You Must Embed Literal JSON Strings
Sometimes the JSON has to come from elsewhere — a file, an API response, a parameter. You need to escape it for embedding in a PowerShell expression.
Single-quoted strings are literal — no escapes interpreted:
$body = '{"name": "Alex", "quote": "She said \"hi\""}'
The \" sequences inside the JSON are literal backslash-quote pairs — exactly what JSON requires. PowerShell doesn't transform them.
Double-quoted strings interpolate variables and process escape sequences:
$name = "Alex"
$body = "{\"name\": \"$name\"}"
Now $name expands, and the inner double quotes need backslash escapes to avoid terminating the outer string. Choose single quotes when there's nothing to interpolate; double quotes when you need variables.
Power Automate — json() and concat() Functions
In Power Automate flows, JSON shows up in two contexts: parsing JSON returned from an action, and constructing JSON to send to an action.
Parsing JSON from a string:
json(triggerOutputs()?['body']?['rawData'])
The json() function parses a string as JSON. Use it whenever you have a string field that contains JSON content (common with HTTP responses or webhook payloads).
Building JSON dynamically:
concat('{"name":"', variables('UserName'), '","email":"', variables('UserEmail'), '"}')
This works but it's fragile — any quote or backslash in the variables breaks the JSON. The safer approach is to use a Compose action that builds the object using the @json() expression:
@{
"name": "@{variables('UserName')}",
"email": "@{variables('UserEmail')}"
}
The Compose action's output is a properly-formatted JSON object. Reference it downstream with outputs('Compose').
Power Automate — Escaping Quotes Inside Variable Values
If a Power Automate variable contains a quote or backslash and you embed it in JSON via concat, the JSON breaks. The fix is to apply replace() first:
concat('{"msg":"', replace(replace(variables('Message'), '\\', '\\\\'), '"', '\\"'), '"}')
This nests two replaces — first escape backslashes, then escape quotes. Order matters: do backslashes first or you double-escape the backslash you just added.
For most flows it's cleaner to skip the manual JSON building and use a Compose action to build the object. Power Automate handles the serialization correctly when you give it a structured object instead of asking it to assemble strings.
Reading JSON Back in Both Tools
PowerShell:
$response = Invoke-RestMethod -Uri "https://api.example.com/users/1" $response.name # Direct property access — no JSON parsing needed
Invoke-RestMethod auto-parses JSON responses. Invoke-WebRequest doesn't — use $response.Content | ConvertFrom-Json in that case.
Power Automate parses JSON responses automatically when the action expects JSON. For raw string responses that contain JSON, use the json() function as shown above.
Both tools save you from the manual escape-and-parse cycle that bash scripts force you into. The lesson: lean on the structured tools (hashtables in PowerShell, Compose actions in Power Automate) instead of building JSON strings by hand.
Escape JSON Without the Pain
For when the script approach gets messy. Paste JSON, get an escaped string.
Open Free JSON Escape / Unescape ToolFrequently Asked Questions
Why does my PowerShell ConvertTo-Json truncate nested objects?
Default Depth is 2. Use -Depth 5 (or higher) to serialize deeper structures fully.
Should I use Invoke-RestMethod or Invoke-WebRequest?
Invoke-RestMethod for JSON APIs — auto-parses the response. Invoke-WebRequest for raw content control.
How do I escape a backslash in Power Automate?
Use replace(value, '\\', '\\\\') to double the backslash. Order matters — escape backslashes before escaping quotes.
Can I send a JSON file directly with Invoke-RestMethod?
Yes: -InFile path/to/body.json or read with Get-Content path -Raw and pass to -Body.

