简体   繁体   中英

Python - Running powershell commands in a subprocess

I am trying to create a program to semi-automate the exporting of VMs from HyperV which requires the use of Get-VM and Export-VM if I want to choose specific VMs to export (which I do), but my current struggle right now is to get these PowerShell commands to run from my python script. As you can see from my code below I've done a lot of tinkering trying to get it to work...

How do I get the code to run Get-VM , which needs to be run with elevated permissions, and have the output be printed into the python console? (I have no need nor particularly want for a PowerShell terminal to open but if it does I don't care, as long as the output also gets put into the python output stream.)

import subprocess, sys, boto3, os
from botocore.exceptions import ClientError
cwd = os.getcwd()
tmp = cwd + "\commandOut.txt"

##def run(cmd):
##    global cwd, tmp
##    cmd = 'powershell Get-VM -ArgumentList "/c "' + tmp + '" -Verb "runAs"'
##    #subprocess.check_output(cmd, shell=True)
##    subprocess.check_output('powershell Get-VM -ArgumentList "/c ".\commandOut.tmp" -Verb "runAs"', shell=True)
##    with open('%TEMP%.\donetstat.tmp', 'x') as f:
##        f.write(p.communicate())
##
##
##if __name__ == '__main__':
##    #hello_command = "Get-VM"
##    #run(hello_command)
##    #with open(tmp, 'w+') as f:
##        #for line in f:
##            #print(line.strip())
##    if hello_info.returncode != 0:
##        print("An error occured: %s", hello_info.stderr)
##    else:
##        print(">", hello_info.stdout)


##import os
##import sys
##import win32com.shell.shell as shell
##ASADMIN = 'asadmin'
##
##if sys.argv[-1] != ASADMIN:
##    script = os.path.abspath(sys.argv[0])
##    params = ' '.join([script] + sys.argv[1:] + [ASADMIN])
##    shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params)
##    sys.exit(0)

stream = subprocess.Popen("Start-Process powershell -Verb runas -ArgumentList \"-NoExit -c Get-VM \"")
output = stream.communicate()
print(output)

Currently, it outputs...

Traceback (most recent call last):
  File "C:\Users\user\Desktop\VM-MigrationProgram\VM-MigrationTool.py", line 38, in <module>
    stream = subprocess.Popen("Start-Process powershell -Verb runas -ArgumentList \"-NoExit -c Get-VM \"")
  File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\subprocess.py", line 966, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\subprocess.py", line 1435, in _execute_child
    hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
FileNotFoundError: [WinError 2] The system cannot find the file specified

So as far as I can tell what I wanted to do is kinda a pain and hasn't really been done before so what I did was make a solution (Go Figure). What I did was create the following script which I plan to use for VM stuff but right now all it does is use the subprocess library to send a cmd command which launches PowerShell with the start-process command starting up another PowerShell as administrator using -Verb runas then it passes in the argument to start minimized, the command you wanna run and a place to put the output which is what we use to get it back into python.

import subprocess, sys, boto3, os, progressbar, time
from botocore.exceptions import ClientError
cwd = os.getcwd()
tmpPSconsole = cwd + "\cPStmp.txt"

def clearConsole(console):
    validateConsoleExists(console)
    temp = []
    temp.clear()
    File = open(console, "w")
    File.writelines(temp)
    File.close()

def validateConsoleExists(console):
    try:
        File = open(console, "x")
        File.close()
    except:
        print("")
        #file exists

def removeTempConsole(console):
    validateConsoleExists(console)
    os.remove(console)

def isEmptyConsole(console):
    validateConsoleExists(console)
    file = open(console, "r")
    data = file.read()
    output = len(data) < 2
    file.close()
    return output

def printConsole(console):
    validateConsoleExists(console)
    file = open(console, "r")
    data = file.read()
    print(data)

def runElevatedPS(command):
    global tmpPSconsole, cwd
    validateConsoleExists(tmpPSconsole)
    clearConsole(tmpPSconsole)
    cmdCommand = "powershell.exe start-process powershell -Verb runas -ArgumentList '-WindowSTyle Minimized -c " + command + " >\"" + tmpPSconsole + "\"'"
    print(cwd + "> ")
    print(cwd + "> " + cmdCommand)
    subprocess.Popen(cmdCommand)
    count = 0
    maxNum=100
    with progressbar.ProgressBar(max_value=maxNum) as bar:
        while(isEmptyConsole(tmpPSconsole)):
            time.sleep(5)
            if(count < 99):
                bar.update(count)
                count += 1
        time.sleep(2)
        count = maxNum - count
        bar.update(count)
    printConsole(tmpPSconsole)

if __name__ == '__main__':
    running_command = "Get-VM"
    runElevatedPS(running_command)
    removeTempConsole(tmpPSconsole)
    end = str(input("Press any key to exit the Program"))

I believe that in my python program's current state the import of boto3 is completely unused and I can't remember if sys was used either but in any case the others definitely do get used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM