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.
CodePudding user response:
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 '"', '\"')