1

I am trying to run AWS CLI in Powershell 7 with a JSON string as parameter. AWS docs make it seem straightforward:

aws route53 ... --change-batch '{"Changes":[{"Action":"UPSERT"}]}'

however, I get an error:

Error parsing parameter '--change-batch': Invalid JSON: Expecting property name enclosed in double quotes: line 1 column 2 (char 1) JSON received: {Changes:[{Action:UPSERT ...

So, it looks like double quotes are stripped at some point.

If I escape the quotes, command works:

aws route53 ... --change-batch '{\"Changes\":[{\"Action\":\"UPSERT\"}]}'

Now, I am trying to use a variable:

aws route53 ... --change-batch '{\"Changes\":[{\"Action\":\"UPSERT\", \"Value\":\"$MY_IP\"}]}'

but the variable is not resolved; that is, $MY_IP is passed to the server. I tried putting the whole string in double-quotes - but it looks like with double quotes internal quotes are removed even if I escape them. Also with backticks - it works as command continuation. I am looking at Microsoft docs - but the results I am getting are clearly different.

I don't think the problem has anything to do with AWS, but AWS CLI gave me a super twisted test case.

Felix
  • 9,248
  • 10
  • 57
  • 89

1 Answers1

1
  • Fundamentally, PowerShell only performs string interpolation in double-quoted strings ("..."), also known as expandable strings: see this answer.

  • The surprising and unfortunate need to explicitly \-escape embedded " chars. in arguments for external programs applies irrespective of which quoting style you use, up to at least PowerShell 7.2.x: see this answer.

Thus, since you need a "..." string for string interpolation (so that variable reference $MY_IP is expanded to its value), you need two layers of escaping of embedded ":

  • `" (or "") in order to satisfy PowerShell's syntax requirements...

  • ... and this escape sequence must additionally be escaped with \ in order for the external program to see the embedded " as such.

Therefore:

# Inside "...", pass-through " must be escaped as \`" (sic)
aws route53 ... --change-batch "{\`"Changes\`":[{\`"Action\`":\"`UPSERT\`", \`"Value\`":\`"$MY_IP\`"}]}"

You can ease the pain with the help of an (expandable) here-string, which obviates the need to escape the embedded " for PowerShell's sake:

# A here-string obviates the need to escape " for PowerShell's sake.
aws route53 ... --change-batch @"
{\"Changes\":[{\"Action\":\"UPSERT\", \"Value\":\"$MY_IP\"}]}
"@

Another option is to perform the \-escaping after the fact, programmatically:

aws route53 ... --change-batch (@"
{"Changes":[{"Action":"UPSERT", "Value":"$MY_IP"}]}
"@ -replace '"', '\"')
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    @Felix :) The need for the extra ``\``-escaping is definitely obscure and a nuisance since v1 - a fix is being tested (as an experimental feature in preview versions of 7.3), but it may be opt-in when it becomes official. If it weren't for this, all you'd need to remember is that in PowerShell `\`` is the escape character, not ``\`` - the distinction between `'...'` (verbatim) and `"..."` (interpolating) strings is more or less the same. – mklement0 Jun 13 '22 at 20:55
  • Now, if only somebody could tell AWS to updated their docs! – Felix Jun 13 '22 at 21:01
  • 1
    @Felix, yeah, that seems broken - there's an `Edit this page on GitHub` link at the bottom, though... - https://github.com/awsdocs/aws-cli-user-guide/tree/master/doc_source/cli-usage-parameters-quoting-strings.md – mklement0 Jun 13 '22 at 21:04
  • I upgraded to powershell 7.3 - and as you said, it is much cleaner! – Felix Nov 12 '22 at 00:19