Windows patching through Ansible gets dismissed as complicated, then adopted by teams who realise the alternative is RDP sessions, manual Windows Update clicks, and no audit trail. WinRM is not SSH, and the setup has sharper edges—but once it is correctly configured and locked down, the automation model is identical to Linux: one playbook, rolling batches, post-reboot validation.
WinRM vs SSH
Ansible supports both WinRM (the traditional path) and OpenSSH (available since Windows Server 2019). For most enterprise environments WinRM is already present; OpenSSH is the cleaner long-term choice if you control the server builds.
| WinRM | OpenSSH | |
|---|---|---|
| Available | Windows Server 2008+ | Windows Server 2019+ |
| Default port | 5985 (HTTP) / 5986 (HTTPS) | 22 |
| Auth options | Basic, Kerberos, NTLM, Certificate | Key-based, password |
| Encryption | Requires HTTPS or message-level encryption | Always encrypted |
| Recommendation | Use HTTPS (5986) only | Preferred on modern builds |
WinRM Setup on the Target (Run Once Per Host)
Run this on each Windows Server target in an elevated PowerShell session:
# Enable and configure WinRM
winrm quickconfig -q
# Create a self-signed certificate for HTTPS (replace with a proper cert in production)
$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation Cert:\LocalMachine\My
New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $cert.Thumbprint -Force
# Open the firewall for WinRM HTTPS
New-NetFirewallRule -DisplayName "WinRM HTTPS" -Direction Inbound -LocalPort 5986 -Protocol TCP -Action Allow
# Set the authentication method
Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true # only if not using Kerberos/NTLM
For domain-joined servers, use Kerberos authentication instead of Basic—it doesn’t transmit credentials over the wire.
Security Warning: WinRM HTTP Is Not Safe
The most common WinRM misconfiguration is leaving HTTP (port 5985) open on the network with Basic authentication enabled. This transmits credentials in Base64 (effectively cleartext) and has been exploited in lateral movement attacks.
Minimum safe configuration:
- HTTPS only (port 5986, valid certificate)
- Basic auth disabled unless you have no Kerberos option
- WinRM firewall rule restricted to the Ansible control node IP
- AllowUnencrypted set to false:
Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $false
Required Collection
Install the ansible.windows collection before running any Windows playbooks:
ansible-galaxy collection install ansible.windows
Add it to requirements.yml:
collections:
- name: ansible.windows
version: ">=2.0.0"
Inventory for Windows Hosts
# inventory/production/hosts.yml
all:
children:
windows_servers:
hosts:
win01.example.com:
win02.example.com:
vars:
ansible_connection: winrm
ansible_winrm_transport: ntlm # or kerberos for domain-joined hosts
ansible_winrm_scheme: https
ansible_port: 5986
ansible_winrm_server_cert_validation: validate # set to ignore only in lab
ansible_user: "DOMAIN\\ansible_svc"
ansible_password: ""
Core Modules: win_updates and win_reboot
Apply all critical and security updates:
---
- name: Patch Windows servers
hosts: windows_servers
serial: 5
tasks:
- name: Install security and critical updates
ansible.windows.win_updates:
category_names:
- SecurityUpdates
- CriticalUpdates
state: installed
reboot: false # handle reboot explicitly below
register: update_result
- name: Show update summary
ansible.builtin.debug:
msg: >
: updates installed,
reboot required:
- name: Reboot if required
ansible.windows.win_reboot:
reboot_timeout: 600
post_reboot_delay: 30
when: update_result.reboot_required | bool
Update Categories
The category_names parameter maps to Windows Update categories:
| Category | Description |
|---|---|
SecurityUpdates |
Microsoft Security Response Center patches |
CriticalUpdates |
Non-security critical fixes |
UpdateRollups |
Cumulative rollup packages |
Updates |
General product updates |
DefinitionUpdates |
Defender / AV signature updates |
Drivers |
Hardware driver updates (usually excluded from server patching) |
For patch management, start with SecurityUpdates and CriticalUpdates. Add UpdateRollups for monthly cumulative patching cycles.
Filtering to Specific KBs
- name: Install a specific KB only
ansible.windows.win_updates:
whitelist:
- KB5034441
state: installed
reboot: false
- name: Exclude a known-bad KB
ansible.windows.win_updates:
category_names:
- SecurityUpdates
blacklist:
- KB5034441 # blocked pending vendor compatibility test
state: installed
reboot: false
Handling Long-Running Updates and Retries
Some cumulative updates take 20–40 minutes. Set reboot_timeout generously and implement retries for the update task:
- name: Install updates with retry
ansible.windows.win_updates:
category_names:
- SecurityUpdates
- CriticalUpdates
state: installed
reboot: false
register: update_result
retries: 3
delay: 60
until: update_result is not failed
- name: Reboot with extended timeout
ansible.windows.win_reboot:
reboot_timeout: 1800 # 30 minutes for slow cumulative updates
post_reboot_delay: 60
test_command: whoami
when: update_result.reboot_required | bool
Post-Patch Service Validation
- name: Verify critical Windows services are running
ansible.windows.win_service:
name: ""
state: started
loop:
- W32Time
- WinRM
- EventLog
- Dnscache
register: svc_check
- name: Fail if services did not recover
ansible.builtin.fail:
msg: " is not running on "
loop: ""
when: item.state != "running"
Scheduling vs On-Demand
For scheduled patching, integrate with the CI/CD pipeline patterns from part four—a cron-triggered GitHub Actions or GitLab CI job that targets the windows_servers group on a defined cadence. On-demand patching (emergency CVE response) uses the same playbook with --limit to scope to affected hosts only:
ansible-playbook -i inventory/production/hosts.yml playbooks/patch-windows.yml \
--limit "win01.example.com,win02.example.com" \
--tags security
Previous: Linux Server Patching with Ansible
Next in the series: Day-to-Day Automation and Reporting — scheduling with AWX, compliance reporting, SIEM integration, and drift detection.
