Search code examples
pythonpowershellpopen

Python popen wait command not behaving as expected


I've a PowerShell script which calls an API and returns 0 or 99 based on if the POST request went through. My PowerShell code:

try
{
    Invoke-RestMethod -uri $url -Method Post -Body $body -ContentType 'application/json' -ErrorAction Stop

    return 0
}
catch
{
    return 99
}

This is how I'm calling the script from my Python script:

req =    subprocess.Popen([r'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe',
                             '-ExecutionPolicy',
                             'Unrestricted',
                             './call.ps1',
                             param1, param2], cwd=os.getcwd())

    print("^^^^^^^")
    result = req.wait() #something is going wrong here
    print("****************")
    print(result)
  
    if result == 0:
        # do something
    else:
        # do something else

Now this is where it's going wrong. Even when the POST request is failing the "result" variable still has "0" and not "99". When I separately run the PowerShell script I can see that it's returning 99 when the POST request is failing. So the problem is not with the PowerShell file it seems.

On debugging Python file, this is what I see on console: (notice the order of print statements in the Python code)

^^^^^^^
99
****************
0

One thing that I don't understand is, what is "99" doing in the output? I'm not even printing the result between "^^^^^" and "*****". So if the PowerShell script is returning 99, why does it change to 0 after "*****"?


Solution

  • The 99 is output created by PowerShell because you used return instead of exit. Because of that the script prints 99 and exits with an exit code of 0 (which is what req.wait() receives). Also, your PowerShell commandline isn't built in a way to actually return a proper exit code from a script, so even if you had used exit instead of return the process would only have returned 0 on success or 1 in case of an error.

    To have PowerShell return a script's exit code you need to either return the exit code yourself

    powershell.exe -Command "&{.\call.ps1; exit $LASTEXITCODE}"
    

    or call the script using the -File parameter

    powershell.exe -File .\call.ps1
    

    To fix the problem change your PowerShell code to this:

    try {
        Invoke-RestMethod -uri $url -Method Post -Body $body -ContentType 'application/json' -ErrorAction Stop
        exit 0
    } catch {
        exit 99
    }
    

    and your Python code to this:

    req = subprocess.Popen([r'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe',
          '-ExecutionPolicy', 'Unrestricted',
          '-File', './test.ps1',
          param1, param2], cwd=os.getcwd())
    
    print("^^^^^^^")
    result = req.wait()
    print("****************")
    print(result)