You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python subprocess调用PowerShell Invoke-Command报错问题

问题:通过Python subprocess调用PowerShell远程会话执行命令失败

我想用Python的subprocess模块在PowerShell中创建New-PSSession远程会话,再通过该会话执行Get-Process命令,但运行代码时报错。

我的代码:

import subprocess

result=subprocess.run(['powershell.exe',' New-PSSession -ComputerName 12.455.66.7777 -Credential (New-Object System.Management.Automation.PSCredential("username",(ConvertTo-SecureString "password" -AsPlainText -Force)))'],capture_output=True)
session=result.stdout.decode().strip()
print(session)
result=subprocess.run(["powershell.exe","-Command", f"Invoke-Command -Session {session} -ScriptBlock {{Get-Process}}"], capture_output=True)
print(result)

错误信息:

CompletedProcess(args=['powershell.exe', '-Command', 'Invoke-Command -Session Id Name ComputerName ComputerType State ConfigurationName Availability\r\n -- ---- ------------ ------------ ----- ----------------- ------------\r\n 1 WinRM1 11.888.32.09 RemoteMachine Opened Microsoft.PowerShell Available -ScriptBlock {Get-Process}'], returncode=1, stdout=b'', stderr=b"At line:3 char:5\r\n+ 1 WinRM1 10.229.78.59 RemoteMachine Opened Mic ...\r\n+ ~~~~~~\r\n表达式或语句中出现意外的标记“WinRM1”。\r\nAt line:2 char:5\r\n+ -- ---- ------------ ------------ ----- --- ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n“--”运算符仅适用于变量或属性。\r\nAt line:2 char:7\r\n+ -- ---- ------------ ------------ ----- --- ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n“--”运算符仅适用于变量或属性。\r\nAt line:2 char:21\r\n+ ... ------------ ------------ ----- ----------- ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n“--”运算符仅适用于变量或属性。\r\nAt line:2 char:23\r\n+ ... ------------ ------------ ----- ------------- ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n“--”运算符仅适用于变量或属性。\r\nAt line:2 char:25\r\n+ ... ------------ ------------ ----- --------------- ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n“--”运算符仅适用于变量或属性。\r\nAt line:2 char:27\r\n+ ... ------------ ------------ ----- ----------------- ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n“--”运算符仅适用于变量或属性。\r\nAt line:2 char:29\r\n+ ... ------------ ------------ ----- ----------------- ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n“--”运算符仅适用于变量或属性。\r\nAt line:2 char:31\r\n+ ... ------------ ------------ ----- ----------------- ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n“--”运算符仅适用于变量或属性。\r\nAt line:2 char:37\r\n+ ... -------- ------------ ----- ----------------- ----- ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n“--”运算符仅适用于变量或属性。\r\n未报告所有分析错误。请纠正报告的错误,然后重试。\r\n + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException\r\n + FullyQualifiedErrorId : UnexpectedToken\r\n \r\n")


问题原因

你犯了一个关键错误:New-PSSession的输出是格式化的表格文本(包含表头、分隔线和会话详情),而不是PowerShell可以直接识别的会话对象。当你把整个表格内容拼到Invoke-Command的-Session参数中时,PowerShell无法解析这堆文本为有效的会话对象,直接抛出语法错误。

解决方案

方法一:在同一个PowerShell会话中完成所有操作(推荐)

跨subprocess调用会丢失PowerShell的变量上下文,最好把创建会话、执行命令、关闭会话的逻辑放在同一个PowerShell命令里执行,这样可以直接使用会话变量,避免传递文本的问题。

修改后的代码:

import subprocess

# 将所有PowerShell逻辑整合为一个命令块
ps_script = '''
# 创建凭据对象
$cred = New-Object System.Management.Automation.PSCredential(
    "username",
    (ConvertTo-SecureString "password" -AsPlainText -Force)
)
# 创建远程会话
$session = New-PSSession -ComputerName 12.455.66.7777 -Credential $cred
# 执行远程命令
Invoke-Command -Session $session -ScriptBlock { Get-Process }
# 关闭会话(避免资源泄漏)
Remove-PSSession -Session $session
'''

# 执行PowerShell命令,指定text=True直接获取字符串输出
result = subprocess.run(
    ['powershell.exe', '-Command', ps_script],
    capture_output=True,
    text=True
)

# 输出结果
print("命令执行结果:")
print(result.stdout)
if result.stderr:
    print("错误信息:")
    print(result.stderr)

方法二:提取会话ID进行调用(不推荐,仅作参考)

如果一定要分两次subprocess调用,需要从New-PSSession的输出中提取会话ID,再通过ID获取会话对象。可以用PowerShell的Select-Object只输出ID值:

修改后的代码:

import subprocess
import re

# 第一步:创建会话并提取ID
create_session_cmd = '''
$cred = New-Object System.Management.Automation.PSCredential(
    "username",
    (ConvertTo-SecureString "password" -AsPlainText -Force)
)
# 仅输出会话ID
New-PSSession -ComputerName 12.455.66.7777 -Credential $cred | Select-Object -ExpandProperty Id
'''

result = subprocess.run(
    ['powershell.exe', '-Command', create_session_cmd],
    capture_output=True,
    text=True
)

session_id = result.stdout.strip()
if not session_id:
    print("创建会话失败:", result.stderr)
else:
    # 第二步:用会话ID执行远程命令
    run_cmd = f'''
    Invoke-Command -Session (Get-PSSession -Id {session_id}) -ScriptBlock {{ Get-Process }}
    # 执行完关闭会话
    Remove-PSSession -Id {session_id}
    '''
    result = subprocess.run(
        ['powershell.exe', '-Command', run_cmd],
        capture_output=True,
        text=True
    )
    print("命令输出:")
    print(result.stdout)
    if result.stderr:
        print("错误信息:")
        print(result.stderr)

注意事项

  • 硬编码用户名和密码存在安全风险,建议使用环境变量或Windows凭据管理器来存储敏感信息
  • 确保目标远程机器已经开启并配置了WinRM服务,且你的本地机器有权限连接
  • 方法一的可靠性更高,因为会话对象在同一个PowerShell进程中维护,不会因为文本解析错误导致失败

内容的提问来源于stack exchange,提问作者lvsilver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 16:35:13