pythonjsonpowershellsubprocessinvoke-restmethod

Python call Powershell Invoke-RestMethod with Json as string into Body


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?


Solution

  • Applying the above to your code, using Python v3.6+ f-strings:

    import requests
    import subprocess
    import base64
    
    credentials = 'login:password'
    url = 'urlXXXurl'
    body = '{"id": 4986986, "key": "2df534ee-270b-4ab4-83fb-1b308febacce", ...}'
    
    # Construct the header as a string representing a PowerShell hashtable literal.
    # Note the the use of {{ and }} to use *literal* { and } chars. in the f-string.
    headers = f"@{{Authorization = 'Basic {base64.b64encode(credentials.encode('ascii')).decode('ascii')}'}}"
    
    # Escape the " chars. in JSON as \", 
    # so that the PowerShell CLI doesn't strip them.
    bodyEscaped = body.replace('"', '\"')
    
    # Note:
    #  Due to use of '...' PowerShell strings, the assumption is that
    #  neither header nor bodyEscaped themselves contain '
    #  If they did, these embedded ' would have to be escaped as ''
    command = f"""\
    powershell.exe -NoProfile -Command
      (
        Invoke-WebRequest -Uri '{url}' -Body '{bodyEscaped}' -Headers {headers} -Method Post -ContentType application/json -UseBasicParsing
      ).Content
    """
    
    response = subprocess.check_call(command)
    

    Note that neither the -NoProfile nor the -Command parameter of the Windows PowerShell CLI are strictly needed here:

    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) "...".


    [1] This assumes that you don't need PowerShell's string interpolation, which requires "..." strings.