Skip to content

muchiny/winrm-rs

winrm-rs

Async WinRM (WS-Management) client for Rust.

Crates.io docs.rs CI License MSRV codecov

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));

Features

  • 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.exe or any executable with arbitrary arguments
  • Full shell lifecycle -- create, execute, receive, signal, delete
  • Streaming output -- start_command + receive_next for incremental polling
  • File transfer -- upload/download files via PowerShell base64 chunking
  • Proxy support -- HTTP proxy for all WinRM requests
  • Async/await -- built on tokio and reqwest
  • TLS support -- rustls backend, optional invalid cert acceptance
  • Cross-platform -- runs from Linux, macOS, or Windows

Installation

cargo add winrm-rs
# For Kerberos support:
cargo add winrm-rs --features kerberos

Usage

Basic authentication

use 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", ""),
)?;

NTLM authentication (default)

let client = WinrmClient::new(
    WinrmConfig::default(), // port 5985, NTLM, no TLS
    WinrmCredentials::new("admin", "password", "MYDOMAIN"),
)?;

Kerberos authentication

// 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", "", ""),
)?;

Certificate authentication

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", "", ""),
)?;

PowerShell execution

let output = client.run_powershell("win-server", "$PSVersionTable | ConvertTo-Json").await?;
assert_eq!(output.exit_code, 0);
println!("{}", String::from_utf8_lossy(&output.stdout));

Raw command execution

let output = client.run_command("win-server", "ipconfig", &["/all"]).await?;
println!("{}", String::from_utf8_lossy(&output.stdout));

Streaming output

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?;

File transfer

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?;

Configuration

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)

Roadmap

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

Comparison

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

Contributing

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 check

License

Licensed under either of Apache License, Version 2.0 or MIT License at your option.

About

Async WinRM (WS-Management) client for Rust with NTLMv2, Kerberos, and Certificate auth

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors