Asynchronous Python library for Windows Remote Management
Project description
awinrm
Asynchronous Python library for Windows Remote Management (WinRM)
awinrm is a fully asynchronous Python client for Windows Remote Management (WinRM). It allows you to execute commands, run PowerShell scripts, transfer files, and maintain interactive shell sessions on remote Windows machines.
���� Acknowledgements
This project is based on the excellent pywinrm library by Alexey Diyan and contributors. While pywinrm uses synchronous requests and external authentication libraries, awinrm was rewritten to be fully async with httpx and uses asyauth for authentication.
��� Features
- Fully Asynchronous - Built with
asyncioandhttpxfor non-blocking I/O - Pure Python Authentication - NTLM, Kerberos, SPNEGO, and CredSSP are all implemented in pure Python via
asyauthandminikerberos(no system dependencies likekrb5orsspirequired!) - Interactive Shells - Create persistent CMD or PowerShell sessions with keepalive support
- File Transfer - Upload and download files via base64-encoded PowerShell commands
- Message Encryption - Automatic GSSAPI message encryption for secure communication over HTTP
- Graceful Termination - Clean handling of shell exits and session timeouts
���� Installation
pip install awinrm
Dependencies
All dependencies are pure Python:
httpx- Async HTTP clientasyauth- Pure Python implementation of NTLM, Kerberos, SPNEGO, CredSSPunicrypto- Cryptographic primitivesaioconsole- Async console input for interactive shells
���� URL Format
awinrm uses URL-based credential specification (from asyauth). The format is:
<transport>+<auth_type>-<auth_method>://<username>:<password>@<host>:<port>/<path>?<options>
Components
| Component | Description | Examples |
|---|---|---|
transport |
HTTP or HTTPS | http, https |
auth_type |
Authentication protocol | ntlm, kerberos, spnego |
auth_method |
Credential type | password, nt, aes, ccache |
username |
User (with optional domain) | user, DOMAIN\user, user@domain.com |
password |
Password or hash | plaintext password or NT hash |
host |
Target hostname or IP | 192.168.1.100, server.domain.com |
port |
WinRM port (optional) | 5985 (HTTP), 5986 (HTTPS) |
options |
Query parameters | dc=, proxytype=, etc. |
URL Examples
# NTLM with password (local account)
"http+ntlm-password://administrator:Password123@192.168.1.100"
# NTLM with domain account
"http+ntlm-password://MYDOMAIN\\admin:Password123@server.mydomain.com"
# Kerberos with password
"http+kerberos-password://NORTH\\vagrant:vagrant@winterfell.north.sevenkingdoms.local/?dc=192.168.56.11"
# Kerberos with ccache (ticket cache)
"http+kerberos-ccache://winterfell.north.sevenkingdoms.local/?ccache=/tmp/krb5cc_1000"
# NTLM with NT hash (pass-the-hash)
"http+ntlm-nt://administrator:aad3b435b51404eeaad3b435b51404ee@192.168.1.100"
# HTTPS with NTLM
"https+ntlm-password://admin:secret@secure-server.domain.com:5986"
Query Parameters
| Parameter | Description |
|---|---|
dc=<ip> |
Domain controller IP (for Kerberos) |
ccache=<path> |
Path to Kerberos credential cache |
proxytype=<type> |
Proxy type (socks5, http) |
proxyhost=<host> |
Proxy hostname |
proxyport=<port> |
Proxy port |
���� API Usage
Basic Command Execution
import asyncio
from awinrm import Session
async def main():
url = "http+ntlm-password://administrator:Password123@192.168.1.100"
async with Session(url) as session:
# Run a command
stdout, stderr, return_code = await session.run_cmd('ipconfig', ('/all',))
print(stdout.decode())
# Run PowerShell
stdout, stderr, return_code = await session.run_ps('Get-Process | Select-Object -First 5')
print(stdout.decode())
asyncio.run(main())
Interactive Shell
import asyncio
from awinrm import Session, ShellTerminatedError
async def main():
url = "http+ntlm-password://administrator:Password123@192.168.1.100"
async with Session(url) as session:
# Create a CMD shell
async with session.create_shell(shell_type='cmd') as shell:
# Send commands
await shell.send_input(b'whoami\r\n')
# Read output
stdout = await shell.stdout.get()
print(stdout.decode())
# Check if shell is still running
if not shell.is_terminated:
await shell.send_input(b'exit\r\n')
asyncio.run(main())
PowerShell Shell
async with Session(url) as session:
# Create a PowerShell shell (recommended for most use cases)
async with session.create_shell(shell_type='powershell') as shell:
await shell.send_input(b'$PSVersionTable\r\n')
stdout = await shell.stdout.get()
print(stdout.decode())
File Transfer
async with Session(url) as session:
# Upload a file
await session.upload_file(
local_path='/tmp/script.ps1',
remote_path='C:\\temp\\script.ps1',
progress_callback=lambda sent, total: print(f'{sent}/{total} bytes')
)
# Download a file
await session.download_file(
remote_path='C:\\Windows\\System32\\drivers\\etc\\hosts',
local_path='/tmp/hosts'
)
# Check if file exists
exists = await session.file_exists('C:\\temp\\script.ps1')
# Get file size
size = await session.get_file_size('C:\\temp\\script.ps1')
Authentication Types
# SPNEGO (auto-negotiates NTLM or Kerberos)
async with Session(url, authtype='spnego') as session:
...
# CredSSP (allows credential delegation / double-hop)
async with Session(url, authtype='credssp') as session:
...
Shell Configuration
async with Session(url) as session:
shell = session.create_shell(
shell_type='powershell', # 'cmd', 'powershell', or 'pwsh'
working_directory='C:\\temp',
env_vars={'MY_VAR': 'value'},
codepage=65001, # UTF-8
keepalive_interval=60, # Seconds between keepalive pings
idle_timeout=300, # Server-side idle timeout
)
async with shell:
...
Custom HTTP Transport
For advanced use cases (proxies, custom SSL, etc.):
import httpx
transport = httpx.AsyncHTTPTransport(
verify=False,
http2=True,
)
async with Session(url, transport=transport, verify=False) as session:
...
Exception Handling
from awinrm import (
Session,
ShellTerminatedError,
ShellNotFoundError,
WinRMError,
WinRMTransportError,
AuthenticationError,
)
async with Session(url) as session:
async with session.create_shell() as shell:
try:
await shell.send_input(b'exit\r\n')
await shell.read_output()
except ShellTerminatedError as e:
print(f"Shell exited with code: {e.exit_code}")
except ShellNotFoundError:
print("Shell was closed by the server")
except AuthenticationError:
print("Authentication failed")
except WinRMTransportError as e:
print(f"HTTP error: {e.code}")
������� Command-Line Tools
awinrm-runcmd
Execute a single command on a remote host:
# Basic usage
awinrm-runcmd 'http+ntlm-password://admin:pass@192.168.1.100' 'ipconfig /all'
# With verbose output
awinrm-runcmd -v 'http+ntlm-password://admin:pass@192.168.1.100' 'whoami'
# Using CredSSP
awinrm-runcmd -a credssp 'http+ntlm-password://admin:pass@192.168.1.100' 'hostname'
awinrm-cmdshell
Interactive remote shell:
# CMD shell
awinrm-cmdshell -s cmd 'http+ntlm-password://admin:pass@192.168.1.100'
# PowerShell shell (default)
awinrm-cmdshell 'http+ntlm-password://admin:pass@192.168.1.100'
# PowerShell Core
awinrm-cmdshell -s pwsh 'http+ntlm-password://admin:pass@192.168.1.100'
# With verbose logging
awinrm-cmdshell -v 'http+kerberos-password://DOMAIN\\user:pass@server/?dc=dc.domain.com'
awinrm-authcheck
Test authentication without executing commands:
# Test NTLM
awinrm-authcheck 'http+ntlm-password://admin:pass@192.168.1.100'
# Test Kerberos
awinrm-authcheck 'http+kerberos-password://DOMAIN\\user:pass@server/?dc=dc.domain.com'
# Verbose mode
awinrm-authcheck -v 'http+ntlm-password://admin:pass@192.168.1.100'
������ WinRM Server Configuration
Enable WinRM (on the Windows target)
# Quick setup (HTTP + NTLM)
winrm quickconfig -q
# Enable CredSSP (for credential delegation)
Enable-WSManCredSSP -Role Server -Force
# Check current config
winrm get winrm/config
Firewall
WinRM uses:
- Port 5985 for HTTP
- Port 5986 for HTTPS
# Allow WinRM through firewall
New-NetFirewallRule -Name "WinRM-HTTP" -DisplayName "WinRM (HTTP)" -Enabled True -Direction Inbound -Protocol TCP -LocalPort 5985 -Action Allow
���� Security Notes
- Use HTTPS in production - HTTP transmits credentials in a recoverable format
- Prefer Kerberos - More secure than NTLM, supports delegation
- Message encryption is automatic - Even over HTTP, NTLM/Kerberos encrypt message payloads
- CredSSP allows delegation - Use when you need to access network resources from the remote host
���� API Reference
Session
| Method | Description |
|---|---|
run_cmd(command, args) |
Execute a command, return (stdout, stderr, rc) |
run_ps(script) |
Execute PowerShell script |
create_shell(shell_type, ...) |
Create interactive shell |
create_powershell(...) |
Convenience method for PowerShell shell |
upload_file(local, remote, callback) |
Upload file to remote |
download_file(remote, local, callback) |
Download file from remote |
file_exists(path) |
Check if remote file exists |
get_file_size(path) |
Get remote file size |
WinRMShell
| Property/Method | Description |
|---|---|
is_terminated |
True if shell has exited |
return_code |
Exit code (if terminated) |
send_input(data) |
Send bytes to shell stdin |
read_output() |
Read available stdout/stderr |
wait_for_termination() |
Block until shell exits |
close() |
Close the shell |
Exceptions
| Exception | Description |
|---|---|
WinRMError |
Base exception for all WinRM errors |
WinRMTransportError |
HTTP-level errors (4xx, 5xx) |
ShellTerminatedError |
Shell has exited (includes exit_code) |
ShellNotFoundError |
Shell no longer exists on server |
AuthenticationError |
Authentication failed (401) |
WinRMOperationTimeoutError |
Operation timed out (retriable) |
���� License
MIT License - see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file awinrm-0.1.0.tar.gz.
File metadata
- Download URL: awinrm-0.1.0.tar.gz
- Upload date:
- Size: 31.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc7132c344a6e8d577dd487c048ca1a6353d6a2586a1c39ea982eda8da99dfdb
|
|
| MD5 |
682ac83cb44879a9a34ce8307cc7e745
|
|
| BLAKE2b-256 |
a4d788f8efec026cb74dfe2227ecf0982868c9f89d6f35d3266a8945a2c669ce
|
File details
Details for the file awinrm-0.1.0-py3-none-any.whl.
File metadata
- Download URL: awinrm-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
560f35bac7ded9e732ea78980d923e76a1f3ae3e054379f70b96d5bc6daa1470
|
|
| MD5 |
7dfa0887df4245bbd450e97cffa1a9cc
|
|
| BLAKE2b-256 |
da23728e5ee593b845843a8d199b9aef83e0083e024327a548240f3951db0f6d
|