What I want to do is pretty simple. I have a PowerShell script that should accept JSON text as a parameter. It looks like it is not simple at all!
I checked these pages in my attempt to learn how it should be done. about_PowerShell_exe, about_Parsing and about_Quoting_Rules. I found no clear explanations. What I see is, actually, contradicts these documents. Command-line rules are not the same as general ones.
I'm on PowerShell 5.1
I use this script for testing:
test.ps1
param($json)
Write-Host $json
I try to pass this JSON text.
{"name" : "value"}
What I see.
powershell .\test.ps1 "{"name" : "value"}"
name : value
No braces. Double quotation marks were completely removed. Let's try to escape them.
powershell .\test.ps1 "{`"name`" : `"value`"}"
Missing closing '}' in statement block or type definition.
The backtick symbol doesn't help. Let's try to double quotation marks. Doubling is a very popular trick in command-line magic.
powershell .\test.ps1 "{""name"" : ""value""}"
The string is missing the terminator: ".
Let's try to triple marks, because why not.
powershell .\test.ps1 "{"""name""" : """value"""}"
Unexpected token ':' in expression or statement.
OK, let's try single quotes.
powershell .\test.ps1 '{"name" : "value"}'
{name : value}
We've got braces, but not double quotation marks. Let's try to escape them once again.
powershell .\test.ps1 '{`"name`" : `"value`"}'
{`name` : `value`}
Something eats our double quotation marks before PS has a chance to escape them.
Doubling?
powershell .\test.ps1 '{""name"" : ""value""}'
{name : value}
Tripling?
powershell .\test.ps1 '{"""name""" : """value"""}'
{"name" : "value"}
It works! How ugly it is!
I wonder if somebody has a good explanation of what's going on. I'd appreciate any link on documentation/article that can explain how it actually works. Tripling quotes doesn't looks too bad for me, but my JSON parameter has several levels of nesting, it looks like I can end up with things like 7 quotes before an element.
-EncodedCommand in powershel.exe gives me a sad feeling that there is no easy solution.
Update. As @mklement0 pointed out, it is a CMD shell that processes this command line first. CMD uses double quotes to handle parameters that have a space in them. Later, Powershell removes pairs of double quotes. Powershell recognizes \ as an escape character. That means that
- The very first and the very last quote will be removed in any case
- We can use \ to escape all internal quotes
powershell .\test.ps1 "{\"name\" : \"value\"}"
Unexpected token ':' in expression or statement.
in this case, this string reached the powershell.exe, {"name" : "value"}
. PowerShell has tried to parse it, and this syntax is not valid. To make it a string, we need another pair of quotes around, and here powershell's single quotes are very helpful.
powershell .\test.ps1 "'{\"name\" : \"value\"}'"
{"name" : "value"}
The better solution is to use -File, as @mklement0 suggested. In this case a parameter won't be interpreted as a PS code.
powershell -File .\test.ps1 "{\"name\" : \"value\"}"
This update has been edited after @mklement0 comment to be factually correct.