import requests
import subprocess
import base64
credentials = "login:password"
url = f'urlXXXurl'
body = '{"id": 4986986, "key": "2df534ee-270b-4ab4-83fb-1b308febacce", ...}'
headers = '"""@{Authorization = 'Basic %s'}"""' % base64.b64encode(credentials.encode("ascii")).decode("ascii")
command = 'powershell.exe Invoke-RestMethod -Method Post -Uri %s -ContentType application/json -Body """%s""" -Headers ( Invoke-Expression %s ) -UseBasicParsing' % (url, body.replace('"', '"'), headers)
response = subprocess.check_call(command)
Is there some kind of necessary conversion, so that JSON would be recognizable by PowerShell?
2
Answers
Finally I used this approach
The only immediate problem with the approach in your question was the use of
"""..."""
around the-Body
argument (resulting in a"..."
string from PowerShell’s perspective):Doing so requires two escaping techniques:
(or
"""
) in order to preserve any"
characters as part of the PowerShell command passed to the the (implied)-Command
parameter of PowerShell’s CLI and`
-escaping of the"
chars. embedded in the value (...
).While you could therefore have used
body.replace('"', '`"')
(note the`
), it is simpler to use'...'
for strings,[1] given that'
doesnot require escaping on the command line and allows embedding
"
characters as-is (albeit as"
via the CLI).There is no need for
( Invoke-Expression %s )
, given that you can formulate the string representing the-Header
argument directly as a PowerShell hashtable literal.As Mathias points out, if you want the command to output a JSON string, use
Invoke-WebRequest
and access the output object’s.Content
property.Invoke-RestMethod
, PowerShell automatically and invariably parses a JSON response into an object graph (which is what necessitated theConvertTo-Json
call in your own answer, which isn’t needed if you use(Invoke-WebRequest).Content
).Applying the above to your code, using Python v3.6+ f-strings:
Note that neither the
-NoProfile
nor the-Command
parameter of the Windows PowerShell CLI are strictly needed here:-NoProfile
bypasses profile (initialization-file) loading and is therefore both potentially faster and makes for a more predictable execution environment.-Command
(-c
) would be implied if not used, but is included for conceptual clarity (not least becausepwsh
, the PowerShell (Core) CLI, now requires-Command
, as it defaults to-File
).Finally, note that – for simplicity – what constitutes the PowerShell command is technically passed as multiple arguments rather than as a single string enclosed in (unescaped)
"..."
.cmd.exe
, were involved in the call (it isn’t withsubprocess.call()
), use of"..."
would be advisable, to prevent accidental interpretation of characters such as&
and|
by that shell."..."
would also be needed in the rare event that your PowerShell command has embedded strings with runs of multiple spaces that need to be preserved as such (without"..."
enclosure, such runs would be folded into a single space each).[1] This assumes that you don’t need PowerShell‘s string interpolation, which requires
"..."
strings.