跳转到主要内容

PowerShell 远程协议和 WinRM for Python

项目描述

pypsrp - Python PowerShell 远程协议客户端库

Test workflow codecov PyPI version

pypsrp 是 PowerShell 远程协议 (PSRP) 和 Windows 远程管理 (WinRM) 服务的 Python 客户端。它允许您从任何可以运行 Python 的机器上对远程 Windows 主机执行命令。

此库公开了 4 种不同类型的 API;

  • 一个简单的客户端 API,可以复制远程 Windows 主机上的文件以及执行进程和 PowerShell 脚本
  • 一个 WSMan 接口,可以执行各种 WSMan 调用,如 SendCreateConnectDisconnect
  • 一个使用基本 WinRM 协议执行 cmd 命令和可执行文件的 Windows 远程 Shell (WinRS) 层
  • 一个 PowerShell 远程协议 (PSRP) 层,允许您创建远程 Runspace 池和 PowerShell 管道

在基本层面上,您可以使用这个库来:

  • 执行 cmd 命令
  • 运行另一个可执行文件
  • 执行 PowerShell 脚本
  • 将文件从本地主机复制到远程 Windows 主机
  • 从远程 Windows 主机获取文件到本地主机
  • 创建包含一个或多个 PowerShell 管道的 Runspace 池并异步执行它们
  • 支持 PSRP 的交互式脚本的参考主机基本实现

目前这个库只支持 WSMan 传输方法,但未来某时将设计支持 SSH(欢迎 Pull Request)。默认情况下,它支持以下与 WSMan 一起使用的身份验证方法:

  • 基本
  • 证书
  • NTLM

它还支持 Negotiate/KerberosCredSSP,但需要安装额外的库。

要求

有关详细信息,请参阅 如何安装

可选要求

以下 Python 库可以安装以添加基本包中没有的额外功能

如何安装

要使用所有基本功能安装 pypsrp,请运行

pip install pypsrp

Kerberos 身份验证

虽然 pypsrp 支持 Kerberos 身份验证,但由于它依赖于系统包的存在,默认情况下不包括 Linux 主机。

要安装这些包,根据您的发行版,运行以下脚本块之一。

对于 Debian/Ubuntu

# For Python 2
apt-get install gcc python-dev libkrb5-dev

# For Python 3
apt-get install gcc python3-dev libkrb5-dev

# To add NTLM to the GSSAPI SPNEGO auth run
apt-get install gss-ntlmssp

对于 RHEL/Centos

yum install gcc python-devel krb5-devel

# To add NTLM to the GSSAPI SPNEGO auth run
yum install gssntlmssp

对于 Fedora

dnf install gcc python-devel krb5-devel

# To add NTLM to the GSSAPI SPNEGO auth run
dnf install gssntlmssp

对于 Arch Linux

pacman -S gcc krb5

安装完成后,可以使用以下命令安装 Python 包

pip install pypsrp[kerberos]

Kerberos 还需要配置以与域通信,但这超出了本页的范围。

CredSSP 身份验证

与 Kerberos 身份验证一样,CredSSP 也受支持,但默认情况下不包括。要添加对 CredSSP 身份验证的支持,请尝试运行以下命令

pip install pypsrp[credssp]

如果失败,您可能需要更新 pip 和 setuptools 到较新版本 pip install -U pip setuptools

如何使用

在此库中使用 3 个主要组件;

  • Transport:处理消息的原始传输到和从服务器
  • Shell:处理用于创建远程 Shell 的 WSMV 或 PSRP 协议细节,该 Shell 在其中运行进程,使用 Connection 发送细节
  • Process:在 Shell 中运行进程或脚本

连接

目前只支持通过 pypsrp.wsman.WSMan 在 HTTP 上通过 WSMan 协议的连接,并提供了 WSMV 规范中的大部分相同功能,包括;

  • 基本、证书、协商、Kerberos 和 CredSSP 身份验证
  • TLS 加密
  • 使用协商、Kerberos 和 CredSSP 身份验证的消息加密
  • 可定义代理

以下是可以用来设置 WSMan 的选项;

  • server:要连接的主机的主机名或 IP 地址
  • max_envelope_size:可以发送到服务器的最大封套大小(以字节为单位),默认为 153600
  • operation_timeout:每个 WSMan 操作的操作超时(以秒为单位),默认为 20。这应该始终低于 read_timeout
  • port:要连接的端口号,如果 ssl=True 则默认为 5986,否则为 5985
  • username:连接时使用的用户名,除certificate外所有认证方式均需提供,对于negotiate/kerberos是可选的
  • passwordusername的密码。由于MacOS/Heimdal GSSAPI实现中的一个错误,在使用Negotiate或Kerberos认证时,此密码将保存在用户的ccache中,请手动运行kdestroy以删除它
  • ssl:是否通过https连接,默认值为True
  • path:连接到的WinRM路径,默认为wsman
  • auth:要使用的认证协议,默认为negotiate,可选值有basiccertificatenegotiatentlmkerberoscredssp
  • cert_validation:是否验证服务器的SSL证书,默认为True。可以设置为False以不验证或指定信任证书的PEM文件路径
  • connection_timeout:创建HTTP连接的超时时间,默认为30
  • read_timeout:在请求后从服务器接收响应的超时时间,默认为30
  • encryption:控制加密设置,默认为auto,可选值为autoalwaysnever。设置为always将始终运行消息加密,即使是在HTTPS上,设置为never则即使在HTTP上也不使用消息加密
  • proxy:连接到远程主机的代理URL
  • no_proxy:是否忽略任何环境代理变量并直接连接到主机,默认为False
  • locale:在每个WSMan请求上设置的wsmv:Locale值。这指定了客户端希望将响应文本翻译成的语言,默认为en-US
  • data_locale:在每个WSMan请求上设置的wsmv:DataLocale值。这指定了响应文本中数值数据的表示格式,默认为locale的值
  • reconnection_retries:在连接问题上的重试次数,默认为0
  • reconnection_backoff:在重连尝试之间的延迟时间(首先暂停X秒,然后暂停2X秒,4X秒,8*X秒,...),默认为2.0
  • certificate_key_pem:用于certificate认证的证书密钥路径
  • certificate_pem:用于certificate认证的证书路径
  • credssp_auth_mechanism:CredSSP中使用的子认证机制,默认为auto,可选值为autontlmkerberos
  • credssp_disable_tlsv1_2:是否使用不安全的TLSv1.0进行CredSSP认证,默认为False
  • credssp_minimum_version:客户端将连接到的CredSSP服务器最低版本,默认为2
  • negotiate_delegate:是否将凭证协商到主机,默认为False。这仅在negotiate认证协商了Kerberos或明确设置了kerberos时有效
  • negotiate_hostname_override:用于计算在Kerberos认证主机时使用的宿主SPN的域名。这仅在negotiate认证协商了Kerberos或明确设置了kerberos时有效
  • negotiate_send_cbt:是否将通道绑定令牌(仅HTTPS)绑定到认证或忽略,默认为True
  • negotiate_service:覆盖用于服务器认证时计算出的SPN的服务部分,默认为WSMAN。这仅在negotiate认证协商了Kerberos或明确设置了kerberos时有效

当通过HTTP运行时,此库默认将强制执行加密,但如果不受支持(基本认证)或主机上不可用,则可以使用HTTPS或使用encryption="never"禁用加密。

计划添加对SSH作为连接的支持,但此功能尚未实现。SSH将在运行PowerShell Core的宿主上工作,但不适用于标准PowerShell。

Shell

此库中可以使用两个Shell,即pypsrp.shell.WinRSpypsrp.powershell.RunspacePool

WinRS 是一个 cmd shell,可以用来执行 cmd 命令,包括但不限于其他可执行文件。以下是可以用来配置 WinRS shell 的选项;

  • wsman:WinRS 只能在 WSMan 上工作,因此这是运行命令所使用的 pypsrp.wsman.WSMan 对象;
  • resource_uri:shell 的资源 uri,默认为 http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
  • id:shell 的 ID,应该保持为 None,因为它由服务器动态创建;
  • input_streams:shell 的输入流,默认为 stdin
  • output_streams:shell 的输出流,默认为 stdout, stderr
  • codepage:shell 的代码页,默认为主机的默认值;
  • environment:用于远程 shell 的环境键/值字典;
  • idle_time_out:shell 的空闲超时时间(秒);
  • lifetime:shell 的总生存时间;
  • name:shell 的名称(仅描述),
  • no_profile:是否创建带有用户配置文件加载的 shell 或不加载,默认为 False
  • working_directory:创建的 shell 的默认工作目录;

RunspacePool 是 PSRP 协议所用的 shell,它被设计为 .NET System.Management.Automation.Runspaces.RunspacePool 类的紧密实现。方法和属性类似,可以大致完成相同的事情。以下是配置 RunspacePool shell 的选项;

  • connection:RunspacePool 用于向远程服务器发送命令的连接对象,目前只支持 WSMan
  • apartment_state:远程线程的 pypsrp.complex_objects.ApartmentState 的整数值,默认为 UNKNOWN
  • thread_options:指定要创建的线程类型的 pypsrp.complex_objects.ThreadOptions 的整数值,默认为 DEFAULT
  • host:本地主机信息实现,默认无主机;
  • configuration_name:要连接到的配置名称,默认为 Microsoft.PowerShell,并可用于指定连接到 Just Enough Administration (JEA);
  • min_runspaces:池可以保持的最小运行空间数量,默认为 1;
  • max_runspaces:池可以保持的最大运行空间数量。每个 PowerShell 管道都在单个 Runspace 中运行,默认为 1;
  • session_key_timeout_ms:从服务器等待会话密钥传输的最大时间;

进程

有两个进程对象可以用于,pypsrp.shell.Process 用于 WinRS shell 和 pypsrp.powershell.PowerShell 用于 RunspacePool shell。这些对象最终用于在远程主机上执行命令、进程或脚本。

Process 用于与 WinRS shell 一起执行 cmd 命令或其他可执行文件。以下用于配置 Process 对象的选项;

  • shell:运行进程的 WinRS shell;
  • executable:要运行的可执行文件或命令;
  • arguments:要传递给可执行文件或命令的参数列表,默认无参数;
  • id:创建的命令的 ID,如果未指定,则动态创建;
  • no_shell:是否在 cmd shell 中创建命令或绕过它,默认为 False。如果为 True,则可执行文件必须是 exe 的完整路径。这仅适用于 2012 R2 之前的旧操作系统(不包括);

要执行进程,调用 .invoke(),一旦完成,stdoutstderrrc 属性将包含命令的输出。

PowerShell 被PSRP协议所使用,它被设计为对 System.Management.Automation.PowerShell 类的紧密实现。方法和属性相似,可以执行大部分相同的功能。以下是可以用来配置 PowerShell 进程的选项;

  • runspace_pool:在 RunspacePool 对象上运行 PowerShell 进程;

要执行进程,调用 .invoke(),其中 outputhad_errosstreams 包含进程的执行状态和输出信息。在调用 invoke 之前,必须添加 cmdlets 或脚本。这可以通过以下方法完成;

  • add_script:将原始 PowerShell 脚本添加到待处理命令中;
  • add_cmdlet:将 cmdlet 添加到待处理命令中;
  • add_parameters:将键/值参数字典添加到最后一个添加的命令中;
  • add_argument:将值参数添加到最后一个添加的命令中;
  • add_statement:设置最后一个命令/脚本作为该管道的结束,这样下一个命令/脚本就像是一个换行符;

以下示例提供了更多详细信息。

示例

如何使用高级客户端API

from pypsrp.client import Client

# this takes in the same kwargs as the WSMan object
with Client("server", username="user", password="password") as client:

    # execute a cmd command
    stdout, stderr, rc = client.execute_cmd("dir")

    stdout, stderr, rc = client.execute_cmd("powershell.exe gci $pwd")
    sanitised_stderr = client.sanitise_clixml(stderr)

    # execute a PowerShell script
    output, streams, had_errors = client.execute_ps('''$path = "%s"
if (Test-Path -Path $path) {
    Remove-Item -Path $path -Force -Recurse
}
New-Item -Path $path -ItemType Directory''' % path)
    output, streams, had_errors = client.execute_ps("New-Item -Path C:\\temp\\folder -ItemType Directory")

    # copy a file from the local host to the remote host
    client.copy("~/file.txt", "C:\\temp\\file.txt")

    # fetch a file from the remote host to the local host
    client.fetch("C:\\temp\\file.txt", "~/file.txt")

如何使用WinRS/Process执行命令

from pypsrp.shell import Process, SignalCode, WinRS
from pypsrp.wsman import WSMan

# creates a http connection with no encryption and basic auth
wsman = WSMan("server", ssl=False, auth="basic", encryption="never",
              username="vagrant", password="vagrant")

with wsman, WinRS(wsman) as shell:
    process = Process(shell, "dir")
    process.invoke()
    process.signal(SignalCode.CTRL_C)

    # execute a process with arguments in the background
    process = Process(shell, "powershell", ["gci", "$pwd"])
    process.begin_invoke()  # start the invocation and return immediately
    process.poll_invoke()  # update the output stream
    process.end_invoke()  # finally wait until the process is finished
    process.signal(SignalCode.CTRL_C)

如何使用RunspacePool/PowerShell执行PowerShell脚本/命令

from pypsrp.powershell import PowerShell, RunspacePool
from pypsrp.wsman import WSMan

# creates a https connection with explicit kerberos auth and implicit credentials
wsman = WSMan("server", auth="kerberos", cert_validation=False))

with wsman, RunspacePool(wsman) as pool:
    # execute 'Get-Process | Select-Object Name'
    ps = PowerShell(pool)
    ps.add_cmdlet("Get-Process").add_cmdlet("Select-Object").add_argument("Name")
    output = ps.invoke()

    # execute 'Get-Process | Select-Object -Property Name'
    ps.add_cmdlet("Get-Process").add_cmdlet("Select-Object")
    ps.add_parameter("Property", "Name")
    ps.begin_invoke()  # execute process in the background
    ps.poll_invoke()  # update the output streams
    ps.end_invoke()  # wait until the process is finished

    # execute 'Get-Process | Select-Object -Property Name; Get-Service audiosrv'
    ps.add_cmdlet("Get-Process").add_cmdlet("Select-Object").add_parameter("Property", "Name")
    ps.add_statement()
    ps.add_cmdlet("Get-Service").add_argument("audiosrc")
    ps.invoke()

    # execute a PowerShell script with input being sent
    script = '''begin {
    $DebugPreference = "Continue"
    Write-Debug -Message "begin"
} process {
    Write-Output -InputObject $input
} end {
    Write-Debug -Message "end"
}
'''
    ps.add_script(script)
    ps.invoke(["string", 1])
    print(ps.output)
    print(ps.streams.debug)

日志记录

此库利用了Python日志配置,并将消息记录到 pypsrp 命名记录器以及 pypsrp.*,其中 *pypsrp 目录中的每个Python脚本。

要为整个库启用日志记录,可以创建以下JSON文件,并用 PYPSRP_LOG_CFG=log.json python script.py 运行您的脚本(此方法在Python 2.6中不可用)。

{
    "version": 1,
    "disable_existing_loggers": false,
    "formatters": {
        "simple": {
            "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
        }
    },

    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "level": "DEBUG",
            "formatter": "simple",
            "stream": "ext://sys.stdout"
        }
    },

    "loggers": {
        "pypsrp": {
            "level": "DEBUG",
            "handlers": ["console"],
            "propagate": "no"
        }
    }
}

您可以通过更改 logger 中的级别值来调整日志级别。

注意:DEBUG 包含大量信息,并将输出客户端发送和接收的所有消息。这可能会导致敏感信息泄露,因此仅应用于调试目的。

测试

任何更改都以拉取请求的形式欢迎,您可以使用以下方式运行当前测试套件;

# make sure tox is installed
pip install tox

# run the tox suite
tox

# or run the test manually for the current Python environment
py.test -v --pep8 --cov pypsrp --cov-report term-missing

许多测试模拟远程Windows主机,但您也可以在真实Windows主机上运行其中许多测试。为此,在运行测试之前设置以下环境变量;

  • PYPSRP_SERVER:远程主机的计算机名或IP地址
  • PYPSRP_USERNAME:连接时使用的用户名
  • PYPSRP_PASSWORD:连接时使用的密码
  • PYPSRR_PORT:连接时使用的端口号(默认:5986
  • PYPSRP_AUTH:用于身份验证的协议(默认:negotiate

有一些需要特定主机设置才能正确运行的进一步集成测试。您可以使用 Vagrant 来设置此主机。这可以通过运行以下命令完成;

# download the Vagrant box and start it up based on the Vagrantfile
vagrant up

# once the above script is complete run the following
vagrant ssh  # password is vagrant

powershell.exe
Register-PSSessionConfiguration -Path "C:\Users\vagrant\Documents\JEARoleSettings.pssc" -Name JEARole -Force

$sec_pass = ConvertTo-SecureString -String "vagrant" -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "vagrant", $sec_pass
$thumbprint = (Get-ChildItem -Path Cert:\LocalMachine\TrustedPeople)[0].Thumbprint

New-Item -Path WSMan:\localhost\ClientCertificate `
    -Subject "vagrant@localhost" `
    -URI * `
    -Issuer $thumbprint `
    -Credential $credential `
    -Force


# exit the remote PowerShell session
exit

# exist the SSH session
exit

完成后,设置以下环境变量以运行集成测试;

  • PYPSRP_RUN_INTEGRATION:设置为任何值
  • PYPSRP_SERVER:设置为 127.0.0.1
  • PYPSRP_USERNAME:设置为 vagrant
  • PYPSRP_PASSWORD:设置为 vagrant
  • PYPSRP_HTTP_PORT:设置为 55985
  • PYPSRP_HTTPS_PORT:设置为 55986
  • PYPSRP_CERT_DIR:设置为项目目录的完整路径

从现在起,您可以运行正常的测试套件,它将运行所有集成测试。

待办事项

  • 查看实现以下传输选项
    • 命名管道
    • SSH
  • 更新CI以使用命名管道进行集成测试
  • 添加Ansible playbooks以进行更好的集成测试
  • 改进Python和.NET对象之间的序列化
  • PSRP的实时交互式控制台

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

pypsrp-0.8.1.tar.gz (385.8 kB 查看哈希值)

上传时间 源代码

构建分发

pypsrp-0.8.1-py3-none-any.whl (88.4 kB 查看哈希值)

上传时间 Python 3

支持