Search code examples
pythonjsonpowershell

JSON text as command line argument when running python script


I have read similar questions relating to passing JSON text as a command line argument with python, but none of the solutions have worked with my case.

I am automating a python script, and the automation runs a powershell script that takes a JSON object generated from a power automate flow. Everything works great until it comes to processing the JSON in my python script.

My goal is to convert the JSON to a dictionary so that I can use the key value pairs in my code.

My powershell script looks like this:


Python script.py {"Items":[{"Name":"foo","File":"\\\\files\\foo\\foo.csv"},{"Name":"bar","File":"\\\\files\\bar\\bar.csv"},{"Name":"baz","File":"\\\\files\\baz\\baz.csv"}]}

My JSON looks like this:

{
    "Items": [
        {
            "Name": "foo",
            "File": "\\\\files\\foo\\foo.csv"
        },
        {
            "Name": "bar",
            "File": "\\\\files\\bar\\bar.csv"
        },
        {
            "Name": "baz",
            "File": "\\\\files\\baz\\baz.csv"
        }
    ]
}

I tried this solution from SO:

if len(sys.argv) > 1:
        d = json.loads(sys.argv[1])
        print(d)

but it returns this error:

Unexpected token ':' in expression or statement.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken

I am unsure how to solve this problem, any suggestions would help!


Solution

  • Depending on the PowerShell version you're using, you will need to handle it differently, if using pwsh 7.3+ the solution is as simple as wrapping your Json string with single-quotes. Otherwise, if using below that, you would need to escape the double-quotes with \, otherwise those get eaten when passed thru your Python script.

    Using this can handle it dynamically:

    $json = @'
    {
        "Items": [
            {
                "Name": "foo",
                "File": "\\\\files\\foo\\foo.csv"
            },
            {
                "Name": "bar",
                "File": "\\\\files\\bar\\bar.csv"
            },
            {
                "Name": "baz",
                "File": "\\\\files\\baz\\baz.csv"
            }
        ]
    }
    '@
    
    if ($PSVersionTable.PSVersion -ge '7.3') {
        Python script.py $json
    }
    else {
        Python script.py $json.Replace('"', '\"')
    }
    

    Then assuming your Python code would be:

    import json
    import sys
    
    if len(sys.argv) > 1:
        d = json.loads(sys.argv[1])
        for i in d['Items']:
            print(i)
    

    Then the output in your PowerShell console would be:

    {'Name': 'foo', 'File': '\\\\files\\foo\\foo.csv'}
    {'Name': 'bar', 'File': '\\\\files\\bar\\bar.csv'}
    {'Name': 'baz', 'File': '\\\\files\\baz\\baz.csv'}
    

    An easier and probably more robust alternative that doesn't require escaping of quotes in any version of PowerShell can be to convert the Json string to Base64 in PowerShell and pass it as argument to your Python script:

    # Json defined here
    $json = @'
    ...
    ...
    '@
    
    $b64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($json))
    Python script.py $b64
    

    Then in Python the code works with a minimal change:

    from base64 import b64decode
    import json
    import sys
    
    if len(sys.argv) > 1:
        d = json.loads(b64decode(sys.argv[1]))
        for i in d['Items']:
            print(i)