Async WinRM (WS-Management) client for Rust.
use winrm_rs::{WinrmClient, WinrmConfig, WinrmCredentials};
let client = WinrmClient::new(
WinrmConfig::default(),
WinrmCredentials {
username: "administrator".into(),
password: "secret".into(),
domain: String::new(),
},
)?;
let output = client.run_powershell("win-server", "Get-Service | ConvertTo-Json").await?;
println!("{}", String::from_utf8_lossy(&output.stdout));- NTLMv2 authentication -- pure Rust, no OpenSSL or system SSPI required
- Basic authentication -- for test environments or HTTPS-secured endpoints
- Kerberos authentication -- via
cross-krb5, feature-gated (--features kerberos) - Certificate authentication -- TLS client certificate auth
- PowerShell execution -- scripts auto-encoded as UTF-16LE Base64 (
-EncodedCommand) - Raw command execution --
cmd.exeor any executable with arbitrary arguments - Full shell lifecycle -- create, execute, receive, signal, delete
- Streaming output --
start_command+receive_nextfor incremental polling - File transfer -- upload/download files via PowerShell base64 chunking
- Proxy support -- HTTP proxy for all WinRM requests
- Async/await -- built on
tokioandreqwest - TLS support --
rustlsbackend, optional invalid cert acceptance - Cross-platform -- runs from Linux, macOS, or Windows
cargo add winrm-rs
# For Kerberos support:
cargo add winrm-rs --features kerberosuse winrm_rs::{AuthMethod, WinrmClient, WinrmConfig, WinrmCredentials};
let client = WinrmClient::new(
WinrmConfig {
auth_method: AuthMethod::Basic,
use_tls: true,
port: 5986,
..WinrmConfig::default()
},
WinrmCredentials::new("admin", "password", ""),
)?;let client = WinrmClient::new(
WinrmConfig::default(), // port 5985, NTLM, no TLS
WinrmCredentials::new("admin", "password", "MYDOMAIN"),
)?;// Requires: cargo add winrm-rs --features kerberos
// Requires: kinit user@REALM has been run
let client = WinrmClient::new(
WinrmConfig {
auth_method: AuthMethod::Kerberos,
..WinrmConfig::default()
},
WinrmCredentials::new("user", "", ""),
)?;let client = WinrmClient::new(
WinrmConfig {
auth_method: AuthMethod::Certificate,
use_tls: true,
port: 5986,
client_cert_pem: Some("/path/to/cert.pem".into()),
client_key_pem: Some("/path/to/key.pem".into()),
..WinrmConfig::default()
},
WinrmCredentials::new("admin", "", ""),
)?;let output = client.run_powershell("win-server", "$PSVersionTable | ConvertTo-Json").await?;
assert_eq!(output.exit_code, 0);
println!("{}", String::from_utf8_lossy(&output.stdout));let output = client.run_command("win-server", "ipconfig", &["/all"]).await?;
println!("{}", String::from_utf8_lossy(&output.stdout));let shell = client.open_shell("win-server").await?;
let cmd_id = shell.start_command("ping", &["-t", "10.0.0.1"]).await?;
loop {
let chunk = shell.receive_next(&cmd_id).await?;
print!("{}", String::from_utf8_lossy(&chunk.stdout));
if chunk.done { break; }
}
shell.close().await?;use std::path::Path;
// Upload
let bytes = client.upload_file("win-server", Path::new("local.bin"), "C:\\remote\\file.bin").await?;
// Download
let bytes = client.download_file("win-server", "C:\\remote\\file.bin", Path::new("local.bin")).await?;WinrmConfig fields:
| Field | Default | Description |
|---|---|---|
port |
5985 |
WinRM HTTP(S) port |
use_tls |
false |
Use HTTPS instead of HTTP |
accept_invalid_certs |
false |
Skip TLS certificate validation |
connect_timeout_secs |
30 |
TCP connection timeout |
operation_timeout_secs |
60 |
WinRM operation timeout (SOAP-level) |
auth_method |
Ntlm |
Basic, Ntlm, Kerberos, or Certificate |
max_envelope_size |
153600 |
Maximum SOAP envelope size in bytes |
max_retries |
0 |
Retries for transient HTTP errors (exponential backoff) |
client_cert_pem |
None |
Path to client cert PEM (Certificate auth) |
client_key_pem |
None |
Path to client key PEM (Certificate auth) |
proxy |
None |
HTTP proxy URL (e.g. http://proxy:8080) |
| Version | Milestone | Status |
|---|---|---|
| v0.1 | NTLMv2 + Basic auth, command execution | Done |
| v0.2 | Shell reuse + stdin piping | Done |
| v0.3 | NTLM sealing, credentials security, retry | Done |
| v0.4 | Kerberos + Certificate auth | Done |
| v0.5 | File transfer, streaming output, proxy | Done |
| v0.6 | CredSSP/TLS channel binding | Planned |
| winrm-rs | pywinrm (Python) | go-winrm (Go) | |
|---|---|---|---|
| Async | native async/await | no | no |
| NTLM | pure Rust (NTLMv2) | via requests-ntlm | built-in |
| Kerberos | via cross-krb5 (v0.4) | via requests-kerberos | built-in |
| Certificate | built-in (v0.4) | yes | yes |
| Encryption | NTLM sealing (v0.3) | via pywinrm[credssp] | built-in |
| TLS backend | rustls | OpenSSL | Go stdlib |
| PowerShell encoding | built-in | built-in | built-in |
| Shell reuse | yes (v0.2) | yes | yes |
| File transfer | base64 chunked (v0.5) | yes | yes |
| Streaming | poll-based (v0.5) | no | no |
| Binary size | single static binary | interpreter | single binary |
Contributions are welcome. Please open an issue to discuss larger changes before submitting a PR.
cargo test --workspace # run tests
cargo clippy --workspace # lint
cargo fmt --check # format checkLicensed under either of Apache License, Version 2.0 or MIT License at your option.