1

Using backslashes to pass a JSON string as a parameter in PowerShell is cumbersome.

executable --json-input '{ \"name\": \"Bob\" }' output.txt

Is there a way to avoid using these backslashes? I tried using single quotes, and doubles quotes in and out without any success. In Python I use triple quotes print(""" here is an example "" """) to avoid character escaping.

Is there a similar solution in PowerShell? One where we never need to worry about reformating a JSON string?

shellwhale
  • 820
  • 1
  • 10
  • 34
  • 1
    `\"` is not a valid escape sequence in PowerShell - are you perhaps referring to some other shell (bash/zsh/cmd)? – Mathias R. Jessen Jul 21 '22 at 14:01
  • No, I'm really using PowerShell. It's strange because it really works on my side, here is the full command I use https://pastebin.com/P3pWBNya – shellwhale Jul 21 '22 at 14:17

2 Answers2

3

PowerShell has here-strings, similar to the multiline literals from Perl (<<<) or Python (""").

The starting quote must be preceded by @ and immediately followed by a line break, whereas the closing quote must follow a newline and be followed by another @ sign:

command --json-input @"
{ "name": "Bob" }
"@ output.txt
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • I edited my question, could you edit your answer too? I added a mandatory argument, how do you handle new lines in that case? – shellwhale Jul 21 '22 at 14:11
  • Your solution answers my question, but I realized that my issue isn't specific to PowerShell. It's specific to the AWS CLI. – shellwhale Jul 21 '22 at 14:21
  • While here-strings are a helpful pointer in general, note that use of regular single-quoted strings too doesn't require escaping `"` characters; e.g., `'{ "name": "Bob" }`. The need for ``\`` escaping embedded `"` chars. only arises to work around PowerShell's broken argument-passing to _external programs_ up to at least 7.2.x, and it applies whether or not you use here-strings. – mklement0 Jul 21 '22 at 14:54
2

The unfortunate need for manual \-escaping of " chars. embedded in string arguments passed to external programs is due to a long-standing PowerShell bug - see this answer - which is finally fixed in PowerShell 7.3+, with selective exceptions on Windows - see this answer.

  • That is to say, you should be able to just pass '{ "name": "Bob" }' - no \-escaping, but the bug prevents that.

To automate this escaping for now, without having to modify a given JSON string, you can apply a regex-based -replace operation, namely $json -replace '([\\]*)"', '$1$1\"'

# Note: only needed for *external executables*, up to at least PowerShell 7.2.x
executable --json-input ('{ "name": "Bob" }' -replace '([\\]*)"', '$1$1\"') output.txt

Note:

  • The above replacement operation also handles escaped embedded " characters correctly.

    • E.g., { "name": "Nat \"King\" Cole" } becomes
      { \"name\": \"Nat \\\"King\\\" Cole\" }, with the \ before " properly escaped as \\

    • See this regex101.com page for an explanation of the regex and replacement operation (for technical reasons, the linked page uses C#'s string syntax, but the solution is equivalent to what is shown here).

  • If you know your JSON input not to contain them, you can simplify to -replace '"', '\"'

mklement0
  • 382,024
  • 64
  • 607
  • 775