subprocess.run() produces different result than manual input

Viewed 641

I am trying to run the following Windows console commands through a Python script:

C:\My\Path\openssl.exe x509 -in C:\My\PEM\mypem.pem -noout -subject > C:\My\Data\data.txt

If put directly into the console, produces the expected 1KB file.

Using subprocess.run() does not. It produces a file, but a 0KB file as if it is not grabbing the stdout response.

What I've tried without success:

# produces b''
args = 'C:/My/Path/openssl.exe x509 -in C:/My/PEM/mypem.pem -noout -subject'
data = subprocess.check_output(args)
print (data)

# produces b''
result = subprocess.Popen('C:/My/Path/openssl.exe x509 -in C:/My/PEM/mypem.pem -noout -subject', stdout = subprocess.PIPE)
print (result.stdout) 

# produces a 0KB data.txt
# probably also producing a b'' thus the 0KB
subprocess.run('C:/My/Path/openssl.exe x509 -in C:/My/PEM/mypem.pem -noout -subject > C:/My/Data/data.txt')
2 Answers

I know this is an old question, but here is my solution:

It is unclear to me absolutely why this is an issue, but I am hypothesizing that OpenSSL must be one shell, then x509 is another shell opened inside OpenSSL and this creates an issue on Windows using subprocess, but not Linux.

You can type separately and sequentially on the CMDline OpenSSL and then x509 to get an idea of what I am talking about. To solve this, I opened up the supposed OpenSSL and x509 shell in one subprocess command then fed the rest of the required data into the process's stdin using a subprocess.PIPE. Here is an example of my program, I am sure you could modify in yours to make this work:

p=subprocess.Popen("openssl x509 -in " + VARS["CLIENTCERT"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
aissuer = p.communicate(bytes("-noout -issuer -nameopt multiline,-align,-esc_msb,utf8,-space_eq;", "utf-8"))[0].decode().strip("\n") # gets stdout

Keep in mind, if you want to run on UNIX and Windows, you should be specifying two commands and running them based on what os.name returns (e.g., nt for Windows...)

Also, you should be setting OpenSSL to your PATH variable so you don't have to specify a path for OpenSSL. To do so, check out Ahmed's answer.

Related