Running powershell script within python script, how to make python print the powershell output while it is running

148,003

Solution 1

  1. Make sure you can run powershell scripts (it is disabled by default). Likely you have already done this. http://technet.microsoft.com/en-us/library/ee176949.aspx

    Set-ExecutionPolicy RemoteSigned
    
  2. Run this python script on your powershell script helloworld.py:

    # -*- coding: iso-8859-1 -*-
    import subprocess, sys
    
    p = subprocess.Popen(["powershell.exe", 
                  "C:\\Users\\USER\\Desktop\\helloworld.ps1"], 
                  stdout=sys.stdout)
    p.communicate()
    

This code is based on python3.4 (or any 3.x series interpreter), though it should work on python2.x series as well.

C:\Users\MacEwin\Desktop>python helloworld.py
Hello World

Solution 2

I don't have Python 2.7 installed, but in Python 3.3 calling Popen with stdout set to sys.stdout worked just fine. Not before I had escaped the backslashes in the path, though.

>>> import subprocess
>>> import sys
>>> p = subprocess.Popen(['powershell.exe', 'C:\\Temp\\test.ps1'], stdout=sys.stdout)
>>> Hello World
_

Solution 3

In addition to the previous answers, I have some suggestions which makes your code more portable.

Instead of setting ExecutionPolicy globally to RemoteSigned (which imposes some security issues) you can use this to set it only for the PowerShell instance created by your Python script:

import subprocess, sys    
p = subprocess.Popen('powershell.exe -ExecutionPolicy RemoteSigned -file "hello world.ps1"', stdout=sys.stdout)
p.communicate()

Note the quotes which allows your PowerShell-script's path/filename to contain spaces.

Furthermore, as shown in the above example, you can use a relative path to call your PowerShell script. The path is relative to your Python workspace directory.

Share:
148,003
user3282276
Author by

user3282276

Updated on July 17, 2021

Comments

  • user3282276
    user3282276 almost 3 years

    I am writing a python script which checks various conditions and runs a powershell script accordingly to help me automate migration from windows XP to windows 7. The powershell script gives its own output giving the user updates as to what is happening. I would like to take the output of the powershell script and print it as output of the python script. I have looked around at some questions which seem to want to do the same thing but they don't seem to be working for me. Initially I tried using

    import subprocess
    subprocess.call(["C:\Users\gu2124\Desktop\helloworld.ps1"])
    

    As was suggested here Run PowerShell function from Python script but I found out that this waits for the program to execute first and does not give output so I found out I need to use subprocess.Popen() as was suggusted here Use Popen to execute a Powershell script in Python, how can I get the Powershell script's output and update it to web page? so I tried this

    import subprocess
    subprocess.Popen(["C:\Users\gu2124\Desktop\helloworld.ps1"], stdout=sys.stdout)
    

    and I get this error

    Traceback (most recent call last):
      File "C:\Users\gu2124\Desktop\pstest.py", line 5, in <module>
        subprocess.Popen(["C:\Users\gu2124\Desktop\helloworld.py1"], stdout=sys.stdout)
      File "C:\Python27\lib\subprocess.py", line 701, in __init__
        errread, errwrite), to_close = self._get_handles(stdin, stdout, stderr)
      File "C:\Python27\lib\subprocess.py", line 848, in _get_handles
        c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
      File "<string>", line 523, in __getattr__
      File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\netref.py", line 150, in __getattr__
        return syncreq(self, consts.HANDLE_GETATTR, name)
      File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\netref.py", line 71, in syncreq
        return conn.sync_request(handler, oid, *args)
      File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\protocol.py", line 434, in sync_request
        raise obj
    
    AttributeError: DebugOutput instance has no attribute 'fileno'
    

    I'm not completely sure what this means but from what I think I understand after reading this AttributeError: StringIO instance has no attribute 'fileno' is that it is because I am messing with the stdout incorrectly. I looked a around more and I found this Why won't my python subprocess code work? where the answers said to use stdout=subprocess.PIPE so I tried this

    import subprocess
    subprocess.Popen(["C:\Users\gu2124\Desktop\helloworld.ps1"], stdout=subprocess.PIPE)
    

    which also does not give me output Finally I saw this http://www.pythonforbeginners.com/os/subprocess-for-system-administrators and changed my code to this

    import subprocess
    p = subprocess.Popen(["powershell","C:\Users\gu2124\Desktop\helloworld.ps1"], stdout=subprocess.PIPE)
    print p.communicate
    

    I thought that it may because I am initially trying to run a powershell script from the command line so I have to open powershell first. When I type these commands directly into the command line it works the way it should but when I run it through the python script it gives this

    <bound method Popen.communicate of <subprocess.Popen object at 0x00000000026E4A90>>
    

    which is an improvement I guess but not the "Hello world" I was expecting. I have no idea what I should try to do next to get this to work. Any help would be greatly appreciated

    Also if the powershell script I am using is needed here it is

    $strString = "Hello World"
    write-host $strString
    
    function ftest{
    $test = "Test"
    write-host $test
    }
    

    EDIT: I tried upgrading to python 3.3 like was suggested in the first answer but I still can't get it to work. I used the command p = subprocess.Popen(['powershell.exe', "C:\\Users\\gu2124\\Desktop\\helloworld.ps1"], stdout=sys.stdout) and am sure the file is there but am getting this error:

    Traceback (most recent call last):
      File "<pyshell#3>", line 1, in <module>
        p = subprocess.Popen(['powershell.exe', "C:\\Users\\gu2124\\Desktop\\helloworld.ps1"], stdout=sys.stdout)
      File "C:\Python27\lib\subprocess.py", line 701, in __init__
        errread, errwrite), to_close = self._get_handles(stdin, stdout, stderr)
      File "C:\Python27\lib\subprocess.py", line 848, in _get_handles
        c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
    UnsupportedOperation: fileno 
    
  • user3282276
    user3282276 about 10 years
    I tried changing my code like you suggested and upgrading to python 3.3 but it still doesn't work...I edited the question to reflect my new output and code
  • not2qubit
    not2qubit about 4 years
    The tricky part here, that is not at all obvious to non PS and Py experts, is that if you have many powershell command-line arguments (or very long/complex one-liners), you have to invoke the shell with an array, where each item is a separate argument. Otherwise you risk wasting hours trying to debug why the output is not what you expect.
  • Billy Cao
    Billy Cao over 2 years
    Using relative path does not work if you run python with admin
  • Stefan
    Stefan over 2 years
    I actually think it does also work when Python is ran using admin privileges. You only have to make sure your Python instance uses the proper workspace directory.