杰瑞科技汇

如何在Python中内嵌执行PowerShell命令?

核心方法概览

主要有以下几种方法可以在 Python 中调用 PowerShell:

如何在Python中内嵌执行PowerShell命令?-图1
(图片来源网络,侵删)
  1. subprocess 模块:这是最通用、最基础的方法,它通过创建一个新的子进程来执行 PowerShell 命令,适用于几乎所有情况,是理解其他方法的基础。
  2. pypsrp (Python PowerShell Remoting Protocol):这是一个专门的第三方库,用于与 PowerShell 远程处理协议 交互,它比 subprocess 更强大、更底层,可以直接与 PowerShell 引擎通信,性能更好,尤其适合执行复杂的、需要交互的脚本。
  3. winrm (Windows Remote Management):通常与 pypsrp 结合使用,或者通过 pywinrm 库实现,它主要用于远程管理 Windows 机器,但也可以在本地执行命令。
  4. ctypespythonnet:这是更底层的方法,直接调用 Windows API 或 .NET 的 CLR(公共语言运行时)。pythonnet 更为常用,它允许你直接在 Python 中使用 .NET 程序集,包括 System.Management.Automation,这种方法功能最强大,但也最复杂。

对于大多数用户来说,subprocesspypsrp 是最常用和推荐的选择。


使用 subprocess 模块 (最常用)

subprocess 是 Python 的标准库,无需额外安装,它就像在 Windows 的命令提示符 或 PowerShell 终端中手动输入命令一样。

执行简单的 PowerShell 命令

import subprocess
# 要执行的 PowerShell 命令
# 注意:命令字符串最好用单引号括起来,以避免与 Python 的双引号冲突
command = 'Get-Process | Select-Object -First 5'
try:
    # 使用 subprocess.run() 执行命令
    # shell=True: 表示命令将通过系统的 shell (这里是 PowerShell) 执行
    # text=True: 表示将 stdout 和 stderr 解码为文本 (Python 3.7+ 的推荐用法)
    # check=True: 如果命令返回非零退出码(表示错误),则会抛出 CalledProcessError 异常
    result = subprocess.run(
        ['powershell.exe', '-Command', command],
        capture_output=True,
        text=True,
        check=True
    )
    # 打印命令的标准输出
    print("命令执行成功!")
    print("输出内容:")
    print(result.stdout)
except subprocess.CalledProcessError as e:
    # 捕获命令执行失败的情况
    print(f"命令执行失败,返回码: {e.returncode}")
    print(f"错误信息: {e.stderr}")
except FileNotFoundError:
    print("错误: 未找到 powershell.exe,请确保您在 Windows 系统上运行。")

代码解释:

  • ['powershell.exe', '-Command', command]: 这是一个列表,推荐使用列表形式而不是字符串,可以避免 shell 注入的风险。
    • powershell.exe: 启动 PowerShell 的可执行文件。
    • -Command: 告诉 PowerShell 接下来要执行一段命令或脚本。
    • command: 要执行的具体命令。
  • capture_output=True: 捕获命令的标准输出和标准错误。
  • text=True: 将捕获到的字节流解码为字符串。
  • check=True: 自动检查返回码,如果命令失败则抛出异常。

执行复杂的 PowerShell 脚本(多行)

如果你的脚本很长或者包含复杂的逻辑,最好将其保存在一个 .ps1 文件中,然后让 PowerShell 去执行它。

如何在Python中内嵌执行PowerShell命令?-图2
(图片来源网络,侵删)

myscript.ps1 文件内容:

# 这是一个示例 PowerShell 脚本
Write-Host "Hello from PowerShell script!"
$currentTime = Get-Date
Write-Host "Current time is: $currentTime"
$osInfo = Get-ComputerInfo
Write-Host "OS Name: $($osInfo.WindowsProductName)"

Python 代码 (run_script.py):

import subprocess
import os
# 获取当前脚本所在目录
script_dir = os.path.dirname(os.path.abspath(__file__))
ps1_file_path = os.path.join(script_dir, 'myscript.ps1')
# 使用 -File 参数直接执行 .ps1 文件
# 这种方式比 -Command 更适合执行脚本文件
try:
    result = subprocess.run(
        ['powershell.exe', '-File', ps1_file_path],
        capture_output=True,
        text=True,
        check=True
    )
    print("脚本执行成功!")
    print("输出内容:")
    print(result.stdout)
except subprocess.CalledProcessError as e:
    print(f"脚本执行失败,返回码: {e.returncode}")
    print(f"错误信息: {e.stderr}")
except FileNotFoundError:
    print("错误: 未找到 powershell.exe 或脚本文件。")

使用 pypsrp 库 (功能更强大)

pypsrp 是一个专门为 PowerShell 设计的库,它不创建新的 shell 进程,而是直接与 PowerShell 引擎通信,这意味着它更快、更轻量,并且可以更好地处理复杂的脚本和流式输出。

安装 pypsrp

首先需要安装这个库:

如何在Python中内嵌执行PowerShell命令?-图3
(图片来源网络,侵删)
pip install pypsrp

执行 PowerShell 命令

from pypsrp.powershell import PowerShell, RunspacePool
from pypsrp.wsman import WSMan
# 连接到本地的 PowerShell 引擎
# 使用 localhost 和默认端口 5985 (HTTP) 或 5986 (HTTPS)
wsman = WSMan("localhost")
runspace_pool = RunspacePool(wsman)
runspace_pool.open()
# 创建 PowerShell 对象
ps = PowerShell(runspace_pool)
# 添加要执行的命令
ps.add_command("Get-Process")
ps.add_parameter("Name", "powershell") # 获取名为 powershell 的进程
try:
    # 执行命令并获取结果
    # invoke() 会返回一个包含所有输出对象的列表
    results = ps.invoke()
    print("命令执行成功!")
    print("输出内容 (对象形式):")
    for item in results:
        # 输出是 Process 对象,可以像访问 Python 对象一样访问其属性
        print(f"  - {item.ProcessName} (PID: {item.Id})")
    # 也可以获取原始的输出流
    # print("\n原始输出流:")
    # print(ps.output)
finally:
    # 关闭 runspace,释放资源
    runspace_pool.close()

pypsrp 的优势:

  • 性能高: 无需创建新进程,直接在现有进程中执行。
  • 交互性强: 可以处理流式输出(输出、错误、进度信息),而 subprocess 通常需要等待命令结束才能获取所有输出。
  • 面向对象: 返回的结果是 PowerShell 对象(如 Process 对象),可以直接访问其属性和方法,比解析文本字符串更可靠。

使用 pythonnet 库 (直接调用 .NET)

如果你想直接使用 .NET 的 System.Management.Automation 命名空间,pythonnet 是不二之选。

安装 pythonnet

pip install pythonnet

执行 PowerShell 命令

import clr
# 添加对 PowerShell 程序集的引用
# 这些是 .NET Framework 的标准程序集
clr.AddReference("System.Management.Automation")
clr.AddReference("System.Management.Automation")
# 导入所需的命名空间
from System.Management.Automation import PowerShell, RunspaceConfiguration
# 创建一个空的 runspace 配置
config = RunspaceConfiguration.Create()
# 创建一个 PowerShell 实例
ps = PowerShell.Create(config)
# 添加脚本命令
ps.AddScript("Get-Service | Where-Object {$_.Status -eq 'Running'} | Select-Object -First 3")
try:
    # 执行脚本
    # invoke() 返回一个 System.Collections.ObjectModel.Collection[IEnumerable]
    results = ps.Invoke()
    print("命令执行成功!")
    print("输出内容 (.NET 对象形式):")
    for service in results:
        # 输出是 ServiceController 对象
        print(f"  - {service.ServiceName}: {service.DisplayName}")
except Exception as e:
    print(f"执行过程中发生错误: {e}")
    # 也可以捕获 PowerShell 的错误流
    # for error in ps.Streams.Error.ReadAll():
    #     print(f"错误: {error.Exception.Message}")
finally:
    # 释放资源
    ps.Dispose()

总结与选择建议

方法 优点 缺点 适用场景
subprocess - Python 标准库,无需安装
- 简单易用,适合快速原型
- 可执行任意命令
- 性能较差(创建新进程)
- 输出是文本,需要手动解析
- 难以处理复杂交互
- 简单的一次性命令执行
- 脚本自动化
- 对性能要求不高的场景
pypsrp - 性能高,不创建新进程
- 输出是对象,易于处理
- 支持流式输出和复杂交互
- 功能强大
- 需要安装第三方库
- 概念比 subprocess 稍复杂
- 需要高性能的 PowerShell 自动化
- 处理复杂脚本和长任务
- 需要精确解析输出对象
pythonnet - 功能最强大,直接访问 .NET
- 与 .NET 生态系统无缝集成
- 可以调用任何 .NET 库
- 安装和配置可能复杂
- 学习曲线陡峭
- 依赖 .NET Framework
- 需要深度集成 .NET 功能
- 构建复杂的混合 Python/.NET 应用
- 对底层控制有极高要求

给你的建议:

  • 如果你只是想在 Python 里跑几个简单的 PowerShell 命令,直接使用 subprocess 就足够了,它最简单直接。
  • 如果你正在构建一个复杂的、需要频繁与 PowerShell 交互的应用,或者发现 subprocess 的性能和输出处理方式满足不了你的需求,那么强烈推荐你学习并使用 pypsrp,它是为这个任务量身定做的最佳选择。
  • 除非你有非常特殊的需求,否则一般不需要使用 pythonnet,因为它引入了额外的复杂性和依赖。
分享:
扫描分享到社交APP
上一篇
下一篇