I encountered a problem when I tried to run a script and pass a JSON string as an argument on Powershell like
PS > $PSVersionTable
Name Value
---- -----
PSVersion 5.1.19041.1320
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
BuildVersion 10.0.19041.1320
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
PS > cat .\foo.py
import sys
print(sys.argv) # I used argparse acutually
PS > python .\foo.py $JsonString
Problem
The problem is the JSON string was parsed and split incorrectly.
PS > $JsonString = '{"foo":"This is the value"}'
PS > python .\foo.py -json $JsonString
# quotes are erased!
['.\\foo.py', '-json', '{foo:This is the value}']
The double quotes are erased by powershell. So next escaped the quotes.
PS > $JsonString = '{\"foo\":\"This is the value\"}'
PS > python .\foo.py -json $JsonString
# split incorrectly!
['.\\foo.py', '-json', '{"foo":"This', 'is', 'the', 'value"}']
Then the quotes remain, however the value is split by the blank space! I read powershell doc and found the way I escaped quotes was wrong. I have to duplicate quotes rather than adding “\”.
$JsonString = '{""foo"":""This is the value""}'
PS > python .\foo.py -json $JsonString
# it's fine
['.\\foo.py', '-json', '{"foo":"This is the value"}']
That works fine, but I found another problem. If the JSON string doesn’t contain any blank spaces, it doesn’t work.
# If the JSON doesn't contain blank
PS > $JsonString = '{""foo"":""Thisisthevalue""}'
PS > python .\foo.py -json $JsonString
# quotes are erased again!
['.\\foo.py', '-json', '{foo:Thisisthevalue}']
Solution
According to the powershell doc, there are two steps when the arguments are passed from powershell to the process.
- Powershell erases the quotes
- Powershell splits the arguments by blank space
Hence, I have to pass JSON string arguments as follows.
# 1. escape double quotes within JSON by duplicating so that powershell doen't erase them
PS > $JsonString = '{"foo":"This is the value"}'.Replace('"','""')
# 2. surround the JSON string by " `" " so that powershell doen't split that
PS > python .\foo.py -json `"$JsonString`"
['.\\foo.py', '-json', '{"foo":"This is the value"}']
# it works wheather it contains blank space or not
# although I still can't understand why the quotes are erased without adding `"
PS > $JsonString = '{"foo":"Thisisthevalue"}'.Replace('"','""')
PS > python .\foo.py -json `"$JsonString`"
['.\\foo.py', '-json', '{"foo":"Thisisthevalue"}']
# if it contains double quotes as value, use " \\"" "
PS > $JsonString = '{"foo":"This is the \\"value\\"."}'.Replace('"','""')
PS > python .\foo.py -json `"$JsonString`"
['.\\foo.py', '-json', '{"foo":"This is the \\"value\\"."}']