Windows (WinRM) module
Deploy any file to any Windows path, then run PowerShell post-deploy scripts. The Windows sibling of the SSH module — same PathSet + ActionSet operator UX, different transport. Distinct from the IIS module, which is dedicated to IIS binding lifecycle.
Type: winrm
Version: 1.0.0
Non-reversible
01When to pick this module
Pick winrm when you want to:
- Drop a PEM / PFX / DER / arbitrary file at a known Windows path
(
C:\inetpub\certs\site.pfx,\\fileserver\share\...). - Run PowerShell after — restart a service, import into a Java keystore via
keytool, run a custom hook script. - Cover Windows targets that aren't IIS: Tomcat, JBoss, custom .NET services, ad-hoc certificate stores.
If your only goal is to update an IIS HTTPS binding, the dedicated IIS module handles binding discovery, app-pool recycling, and old-cert cleanup automatically.
02Server-side prerequisites
Run on each Windows host (PowerShell as Administrator):
# Enable WinRM
Enable-PSRemoting -Force
# HTTPS listener (production: replace the self-signed cert with a real one)
winrm quickconfig -transport:https
# Firewall — open both ports if you intend to use both
New-NetFirewallRule -Name 'WinRM-HTTP' -DisplayName 'WinRM HTTP' `
-Enabled True -Direction Inbound -Protocol TCP -LocalPort 5985 -Action Allow
New-NetFirewallRule -Name 'WinRM-HTTPS' -DisplayName 'WinRM HTTPS' `
-Enabled True -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow
# Optional: raise envelope size for large file transfers
Set-Item WSMan:\localhost\MaxEnvelopeSizekb 8192
03Authentication methods
NTLM (default)
Works with local accounts and domain accounts. Provide username as just
svc-certdeploy (local) or DOMAIN\svc-certdeploy
(domain), or set the Domain field on the target separately.
Basic
Username/password sent over the wire. Use only with TLS enabled — the target form warns when you mix Basic with plain HTTP.
Kerberos (first-class)
Set auth_type=kerberos + Domain field (the Kerberos realm,
e.g. CORP.LOCAL). The CertAutoPilot host needs a valid
krb5.conf for KDC discovery (typical Linux installer ships
/etc/krb5.conf; symlink or set the KRB5_CONFIG
environment variable for non-default paths). The library auto-derives the
SPN as HTTP/<hostname>.
CredSSP (multi-hop delegation) is not supported in this version. Most domain-joined scenarios are covered by Kerberos.
04PathSet — where files go
The PathSet (and ActionSet) you bind to a WinRM target must be created with
target_kind: "windows". The form's PathSet/ActionSet dropdowns filter
to Windows-scoped resources only; the backend rejects mismatched bindings at
create/update time. Reusing a Linux PathSet on a WinRM target (or vice versa)
is not allowed — POSIX paths and owner/mode have no Windows equivalent.
Identical shape to the SSH module's PathSet. Each entry pairs a content
source with an absolute Windows path. Sources:
cert— leaf certificate PEMchain— chain (intermediates) PEMfullchain— leaf + chain PEMprivate_key— private key PEMcombined— leaf + chain + key in one PEM file
Format defaults to pem; der is supported for
cert and private_key sources.
Path validation rejects: relative paths, .. traversal segments,
null bytes, Windows reserved device names (CON, NUL, PRN, AUX, COM1–9, LPT1–9),
forbidden filename characters (< > : " | ? *), and components
with trailing dots or spaces (Windows strips them silently). Drive-letter and
UNC paths are both accepted.
05ActionSet — what runs after
Two modes:
command mode
List of PowerShell commands. Run one-by-one. Optional
allowed_commands regex allowlist (defence in depth — operator
mistypes a destructive command and the regex blocks it).
script_inline mode
Multi-line script body. Uploaded to a remote temp path
($env:TEMP\certautopilot-XXXX.ps1) via the chunked WriteFile
transport, ACL-restricted to the executing user, run with
-NoProfile -NonInteractive -ExecutionPolicy Bypass -File, then
removed (best-effort cleanup).
Operator picks the shell: powershell.exe (Windows PowerShell 5.1,
default — present on every modern Windows Server) or pwsh.exe
(PowerShell 7+, must be installed on the target).
06Variable substitution
Project variables expand via the ${{ NAME }} placeholder syntax.
Values are PowerShell-escape-aware: a hostile project variable
value $(Get-Process) is substituted as the literal string
'$(Get-Process)' rather than an executable sub-expression. Same
threat-model fix as the SSH module's shell-escape work; consult
project variables for syntax
details and escape semantics.
07Worked example: cert + Tomcat reload
PathSet:
C:\Tomcat\conf\ssl\fullchain.pem→ sourcefullchainC:\Tomcat\conf\ssl\privkey.pem→ sourceprivate_key
ActionSet (mode script_inline, shell powershell.exe):
$ErrorActionPreference = 'Stop'
# Convert PEM → JKS for Tomcat
keytool -importkeystore `
-srckeystore "C:\Tomcat\conf\ssl\fullchain.pem" `
-srcstoretype PEM `
-destkeystore "C:\Tomcat\conf\ssl\keystore.jks" `
-deststoretype JKS `
-alias tomcat `
-storepass "${{ KEYSTORE_PASS }}"
Restart-Service -Name Tomcat9
Write-Output "tomcat reloaded with new cert"
08Rollback
Not supported by the framework. Same posture as the IIS, NetScaler, F5 BIG-IP,
and Webhook modules. The module is generic by design — it cannot know what your
ActionSet did (restart a service? reconfigure a binding? import into a Java
keystore?), so it cannot reliably undo it. If you need a backout, embed it in
your ActionSet: take a .bak with Copy-Item before
overwrite, keep a Restore-Item path on hand, or roll service state
forward through your existing ops tooling.
09Limits + performance
| Knob | Default | Note |
|---|---|---|
| File transfer rate | ~60–300 KB/sec | WAN-RTT bound; chunked base64 + certutil decode. |
| Per-file size cap | 100 MB | Configurable on the target via max_file_size_bytes. Raise only if you genuinely need to push > 100 MB. |
| Per-script size cap | ~256 KB UTF-8 source | UTF-16LE doubles bytes; we cap before WSMan envelope quota. |
| Per-target concurrency | 10 | Module-level; clamped on the upper end. |
| Per-target timeout | 5 min | target_timeout_seconds on the module config. |
| Per-command timeout | 60 sec | command_timeout_seconds on the target; ActionSet timeout_seconds overrides per-command. |
| Output truncation | 16 KB | Per-command stdout+stderr; PowerShell verbosity bounded. |
10Error codes
The module emits structured WINRM_* error codes for retry
classification:
WINRM_CONNECT— dial / DNS / TLS handshake failure (network class)WINRM_AUTH— 401, NTLM/Kerberos rejection, "Access denied" (auth class)WINRM_TIMEOUT— context deadline exceeded (transient — retried)WINRM_EXEC— non-zero PowerShell exit (transient — retried)WINRM_PS_SYNTAX— ParserError detected in stderr (validation — not retried)WINRM_FILE— file transfer failure (transient — retried)WINRM_VALIDATION— operator config error (path, run_as)WINRM_QUOTA— MaxEnvelopeSize exceeded (permanent — operator must raise the quota)
11vs. the IIS module
| Aspect | winrm | iis |
|---|---|---|
| Scope | Generic file deploy + script | IIS binding lifecycle |
| PathSet / ActionSet | Yes | No (uses fixed IIS scripts) |
| Concurrency | Parallel (10 default) | Sequential |
| Auth | NTLM, Basic, Kerberos | NTLM, Basic |
| Rollback | No (operator scripts it in the ActionSet) | No |
| Picks IIS bindings automatically | No (operator scripts it) | Yes |