PowerShell 远程协议和 WinRM for Python
项目描述
pypsrp - Python PowerShell 远程协议客户端库
pypsrp 是 PowerShell 远程协议 (PSRP) 和 Windows 远程管理 (WinRM) 服务的 Python 客户端。它允许您从任何可以运行 Python 的机器上对远程 Windows 主机执行命令。
此库公开了 4 种不同类型的 API;
- 一个简单的客户端 API,可以复制远程 Windows 主机上的文件以及执行进程和 PowerShell 脚本
- 一个 WSMan 接口,可以执行各种 WSMan 调用,如
Send
、Create
、Connect
、Disconnect
等 - 一个使用基本 WinRM 协议执行 cmd 命令和可执行文件的 Windows 远程 Shell (WinRS) 层
- 一个 PowerShell 远程协议 (PSRP) 层,允许您创建远程 Runspace 池和 PowerShell 管道
在基本层面上,您可以使用这个库来:
- 执行 cmd 命令
- 运行另一个可执行文件
- 执行 PowerShell 脚本
- 将文件从本地主机复制到远程 Windows 主机
- 从远程 Windows 主机获取文件到本地主机
- 创建包含一个或多个 PowerShell 管道的 Runspace 池并异步执行它们
- 支持 PSRP 的交互式脚本的参考主机基本实现
目前这个库只支持 WSMan 传输方法,但未来某时将设计支持 SSH(欢迎 Pull Request)。默认情况下,它支持以下与 WSMan 一起使用的身份验证方法:
- 基本
- 证书
- NTLM
它还支持 Negotiate/Kerberos
和 CredSSP
,但需要安装额外的库。
要求
有关详细信息,请参阅 如何安装
- CPython 3.6+
- cryptography
- pyspnego
- requests
可选要求
以下 Python 库可以安装以添加基本包中没有的额外功能
- python-gssapi 用于 Linux 上的 Kerberos 身份验证
- pykrb5 用于 Linux 上的 Kerberos 身份验证
- requests-credssp 用于 CredSSP 身份验证
如何安装
要使用所有基本功能安装 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
是可选的password
:username
的密码。由于MacOS/Heimdal GSSAPI实现中的一个错误,在使用Negotiate或Kerberos认证时,此密码将保存在用户的ccache中,请手动运行kdestroy
以删除它ssl
:是否通过https
连接,默认值为True
path
:连接到的WinRM路径,默认为wsman
auth
:要使用的认证协议,默认为negotiate
,可选值有basic
、certificate
、negotiate
、ntlm
、kerberos
、credssp
cert_validation
:是否验证服务器的SSL证书,默认为True
。可以设置为False
以不验证或指定信任证书的PEM文件路径connection_timeout
:创建HTTP连接的超时时间,默认为30
read_timeout
:在请求后从服务器接收响应的超时时间,默认为30
encryption
:控制加密设置,默认为auto
,可选值为auto
、always
、never
。设置为always
将始终运行消息加密,即使是在HTTPS上,设置为never
则即使在HTTP上也不使用消息加密proxy
:连接到远程主机的代理URLno_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
,可选值为auto
、ntlm
或kerberos
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.WinRS
和pypsrp.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()
,一旦完成,stdout
、stderr
和 rc
属性将包含命令的输出。
PowerShell
被PSRP协议所使用,它被设计为对 System.Management.Automation.PowerShell 类的紧密实现。方法和属性相似,可以执行大部分相同的功能。以下是可以用来配置 PowerShell
进程的选项;
runspace_pool
:在RunspacePool
对象上运行PowerShell
进程;
要执行进程,调用 .invoke()
,其中 output
、had_erros
和 streams
包含进程的执行状态和输出信息。在调用 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的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | f5500acd11dfe742d51b7fbb61321ba721038a300d67763dc52babe709db65e7 |
|
MD5 | 55d346022eafdd9cc825e4ad111a98ae |
|
BLAKE2b-256 | 57da3d9295972c20624c79843c1c14cf06fc6b0575ba786c1f72d6ca5bc5b9d5 |
pypsrp-0.8.1-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 0101345ceb415896fed9b056e7b77d65312089ddc73c4286247ccf1859d4bc4d |
|
MD5 | 1b9cd53685e93025c2bced10e53ecd4d |
|
BLAKE2b-256 | 9deccd0d634f31e49fa260b0fa813b9b52c97ed52f3fe03e22da290b9a3bcbd9 |