3

I read I think all the articles on escaping strings in PowerShell, but I still haven't found the solution that would satisfy me.

Suppose I have a file foo.json that contains a JSON string. I need to pass the JSON string to a program as an argument.

In bash, this works just fine:

myprogram "$(cat ~/foo.json)"

In PowerShell, when I read the contents of the file normally and pass it in, the receiving program complains about there not being quotes around the keys and the values.

What I've come up with is:

$json = (get-content ~/foo.json | Out-String) -replace '"','""' myprogram $json

Is there a less awkward way to do this in PowerShell? I've resorted to exiting the session, running the command in bash, then starting the session again.

Tatiana Racheva
  • 1,225
  • 1
  • 12
  • 31
  • 1
    In json files, all keys and values are quoted, except for numeric values. If the json file you want to pass as a string contains these quote characters, they will not be altered if you read it in with `myprogram (Get-Content foo.json -Raw)` – Theo Oct 15 '18 at 19:06
  • @Theo: The problem here is PowerShell's (lack of) quoting when passing a string with embedded `"` chars. to an _external program_. – mklement0 Oct 15 '18 at 19:44

1 Answers1

9

Unfortunately, PowerShell's passing of arguments with embedded double quotes to external programs is broken up to at least PowerShell 7.2, requiring you to manually \-escape them as \":

  • See this answer for more information about the underlying problem.

A robust workaround requires not only replacing all " with \", but also doubling any \ immediately preceding them.

# Note: If your JSON has no embedded *escaped* double quotes
#       - \" - you can get away with: -replace '"', '\"'
myprogram ((Get-Content -Raw ~/foo.json) -replace '([\\]*)"', '$1$1\"')

Note the use of Get-Content -Raw, which is preferable to Get-Content ... | Out-String for reading the entire file into a single, multi-line string, but note that it requires PSv3+.


Assuming that your JSON contains either no or only \" escape sequences, a simpler workaround, discovered by Vivere, is to encode the JSON strings as JSON again, via ConvertTo-Json:

# Works, but only if your JSON contains no escape sequences
# such as \n or \\
myprogram (Get-Content -Raw ~/foo.json | ConvertTo-Json)
mklement0
  • 312,089
  • 56
  • 508
  • 622
  • Also, is there a reason to prefer \" to ""? – Tatiana Racheva Oct 16 '18 at 18:15
  • Glad to hear it, @TatianaRacheva. You may prefer `\`"` for consistency, given that `\`` is the general escape character, but `""` works fine inside `"..."`; note that inside `'...'`, `''` is the only way to embed single quotes. – mklement0 Oct 16 '18 at 18:55
  • 1
    @Vivere, that's handy, and I've added it as an alternative to the answer, but note that it isn't fully robust - please see my update, which now also shows a fully robust `-replace` solution. – mklement0 Jan 12 '22 at 16:14