在python脚本中运行powershell脚本,如何让python在运行时打印powershell输出

Posted

技术标签:

【中文标题】在python脚本中运行powershell脚本,如何让python在运行时打印powershell输出【英文标题】:Running powershell script within python script, how to make python print the powershell output while it is running 【发布时间】:2014-03-23 14:02:52 【问题描述】:

我正在编写一个 python 脚本,它检查各种条件并相应地运行一个 powershell 脚本,以帮助我自动从 windows XP 迁移到 windows 7。powershell 脚本提供自己的输出,让用户了解正在发生的事情。我想获取 powershell 脚本的输出并将其打印为 python 脚本的输出。我环顾了一些似乎想做同样事情的问题,但它们似乎对我不起作用。最初我尝试使用

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

正如这里所建议的Run PowerShell function from Python script,但我发现这会等待程序首先执行并且不提供输出,所以我发现我需要使用subprocess.Popen(),正如这里所建议的Use Popen to execute a Powershell script in Python, how can I get the Powershell script's output and update it to web page?,所以我尝试了这个

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

我得到这个错误

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'

我不完全确定这意味着什么,但从我阅读此AttributeError: StringIO instance has no attribute 'fileno' 后的理解来看,这是因为我错误地弄乱了标准输出。我环顾四周,发现了这个Why won't my python subprocess code work?,答案说要使用stdout=subprocess.PIPE,所以我尝试了这个

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

这也没有给我输出 最后我看到了这个http://www.pythonforbeginners.com/os/subprocess-for-system-administrators,把我的代码改成了这个

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

我认为这可能是因为我最初尝试从命令行运行 powershell 脚本,所以我必须先打开 powershell。当我直接在命令行中输入这些命令时,它会以应有的方式工作,但是当我通过 python 脚本运行它时,它会给出这个

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

我猜这是一个改进,但不是我期待的“Hello world”。 我不知道接下来我应该怎么做才能让它发挥作用。任何帮助将不胜感激

另外,如果这里需要我使用的 powershell 脚本,那就是

$strString = "Hello World"
write-host $strString

function ftest
$test = "Test"
write-host $test

编辑:我尝试像第一个答案中建议的那样升级到 python 3.3,但我仍然无法让它工作。我使用了命令p = subprocess.Popen(['powershell.exe', "C:\\Users\\gu2124\\Desktop\\helloworld.ps1"], stdout=sys.stdout) 并确定文件在那里,但收到此错误:

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 

【问题讨论】:

当您编写print p.communicate 时,您正在打印出方法对象,而不是打印出运行的方法的结果。您需要将其更改为 print p.communciate() 以获得您想要的结果。 您也没有导入 sys 模块,这会导致调用 sys.stdout 失败。 UnsupportedOperation 表示您的操作系统不支持 fileno()。如果你看这里:forums.devshed.com/python-programming-11/…,它指的是提到 fileno() 的文档仅适用于 unix。如果subprocess.Popen() 不适合您,您可以尝试os.system(),尽管它已被弃用。 【参考方案1】:

我没有安装 Python 2.7,但在 Python 3.3 中调用 Popen 并将 stdout 设置为 sys.stdout 工作得很好。不过,在我避开路径中的反斜杠之前。

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

【讨论】:

我尝试按照您的建议更改我的代码并升级到 python 3.3,但它仍然不起作用...我编辑了问题以反映我的新输出和代码【参考方案2】:

    确保您可以运行 powershell 脚本(默认情况下禁用)。您可能已经这样做了。 http://technet.microsoft.com/en-us/library/ee176949.aspx

    Set-ExecutionPolicy RemoteSigned
    

    在你的powershell脚本helloworld.py上运行这个python脚本:

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

此代码基于 python3.4(或任何 3.x 系列解释器),但它也应适用于 python2.x 系列。

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

【讨论】:

这里的棘手部分,对于非 PS 和 Py 专家来说根本不明显,如果你有许多 powershell 命令行参数(或非常长/复杂的单行),你 必须 使用数组调用 shell,其中每个项目都是一个单独的参数。否则,您可能会浪费时间尝试调试为什么输出不是您所期望的。【参考方案3】:

除了前面的答案,我还有一些建议可以让你的代码更便携。

除了将ExecutionPolicy 全局设置为RemoteSigned(这会带来一些安全问题)之外,您还可以使用它来仅为您的 Python 脚本创建的 PowerShell 实例设置它:

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

请注意允许 PowerShell 脚本的路径/文件名包含空格的引号。

此外,如上例所示,您可以使用相对路径来调用您的 PowerShell 脚本。该路径是相对于您的 Python 工作区目录的。

【讨论】:

如果您使用管理员运行 python,则使用相对路径不起作用 我实际上认为当使用管理员权限运行 Python 时它也可以工作。您只需确保您的 Python 实例使用正确的工作区目录。

以上是关于在python脚本中运行powershell脚本,如何让python在运行时打印powershell输出的主要内容,如果未能解决你的问题,请参考以下文章

用于运行Python脚本的Powershell脚本

如何使用 Python 中的参数运行 PowerShell 脚本

python虚拟环境virtualenv与powershell 运行脚本由执行策略引起的问题

powershell 远程执行bat脚本,去启动一个应用,如何让应用一直运行,powershell能正常退出?

使用 PowerShell 调用服务器以运行 python 脚本:无法打开文件 [Errno 13] 权限被拒绝

powershell怎么运行