Blog
Wild & Free Tools

Escape JSON for PowerShell and Power Automate — Practical Patterns

Last updated: February 2026 6 min read
Quick Answer

Table of Contents

  1. PowerShell — Build, Don't Escape
  2. When You Must Embed JSON Strings
  3. Power Automate — json() and concat()
  4. Power Automate — Escaping Special Values
  5. Reading JSON Back in Both
  6. Frequently Asked Questions

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.

Sell Custom Apparel — We Handle Printing & Free Shipping

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 Tool

Frequently 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.

David Rosenberg
David Rosenberg Technical Writer

David spent ten years as a software developer before shifting to technical writing covering developer productivity tools.

More articles by David →
Launch Your Own Clothing Brand — No Inventory, No Risk