Can Powershell read code from stdin?

倾然丶 夕夏残阳落幕 提交于 2021-01-27 06:45:25

问题


I'm trying to run a Powershell subprocess from Python. I need to send Powershell code from Python to the child process. I've got this far:

import subprocess
import time

args = ["powershell", "-NoProfile", "-InputFormat None", "-NonInteractive"]

startTime = time.time()
process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

process.stdin.write("Write-Host 'FINISHED';".encode("utf-8"))

result = ''
while 'FINISHED' not in result:
    result += process.stdout.read(32).decode('utf-8')
    if time.time() > startTime + 5:
        raise TimeoutError(result)
print(result)

This times out, because nothing ever gets written to stdout. I think the Write-Host cmdlet never gets executed. Even the simple bash/Cygwin code echo "Write-Host 'FINISHED';" | powershell doesn't seem to do the job.

For comparison, sending the code block using the -Command flag works correctly.

How can I convince Powershell to run the code which I'm sending to stdin?


回答1:


There a couple of things you can consider:

  1. Invoke PowerShell in a mode where you provide it with a script file which it should execute. Write this script file prior to calling the subprocess. Use the -File <FilePath> parameter for PowerShell (cf. the docs)

  2. If you really want to go with the stdin technique, you might be missing a newline character after the command. If this does not help, you might need to send another control character that tells PowerShell that input EOF is reached. You definitely need to consult the PowerShell docs for finding out how to 'terminate' commands on stdin. One thing you definitely need is the -Command - arguments: The value of Command can be "-", a string. or a script block. If the value of Command is "-", the command text is read from standard input. You may also want to look at this little hack: https://stackoverflow.com/a/13877874/145400

  3. If you only want to execute one command, you can simplify your code by using out, err = subprocess.communicate(in)




回答2:


I had trouble with a similar task, but I was able to solve it.

First my example code:

import subprocess

args = ["powershell.exe", "-Command", r"-"]
process = subprocess.Popen(args, stdin = subprocess.PIPE, stdout =   subprocess.PIPE)

process.stdin.write(b"$data = Get-ChildItem C:\\temp\r\n")
process.stdin.write(b"Write-Host 'Finished 1st command'\r\n")
process.stdin.write(b"$data | Export-Clixml -Path c:\\temp\state.xml\r\n")
process.stdin.write(b"Write-Host 'Finished 2nd command'\r\n")

output = process.communicate()[0]

print(output.decode("utf-8"))
print("done")

The main issue was the correct argument list args. It is required to start the powershell with the -Command-flag, followed by "-" as indicated by Jan-Philipp.

Another mystery was the end-of-line character that is required to get the stuff executed. \r\n works quite well.

Getting the output of the Powershell is still an issue. But if you don't care about realtime, you can collect the output after finishing all executions by calling

output = process.communicate()[0]

However, the active Powershell will be terminated afterwards.



来源:https://stackoverflow.com/questions/21833829/can-powershell-read-code-from-stdin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!