Why Bother with Ansible for Windows in 2026?
Let’s be honest: Ansible + Windows has always felt like a second-class citizen. On Linux, you SSH in and you’re done. On Windows, you’re dealing with WinRM, PowerShell Remoting, Kerberos tickets, and a dozen authentication protocols that sound like they were designed by a committee in 2005.
But here’s the reality check. My team took on a client last year running their core business on Windows Server 2022, with a bunch of 2016 stragglers dragging their feet. The boss said “we need automation,” and the knee-jerk reaction was PowerShell scripts. The problem? Scripts scattered across fifty servers, no version control, no one knowing who changed what.
That’s where Ansible earns its keep. Not because it’s better than PowerShell—it’s not, for pure Windows tasks. But because it gives you a declarative framework. You tell it the end state, and it figures out the path. That’s powerful when you’re managing a fleet, not just one box.
Over on Reddit’s r/homelab, someone nailed the sentiment: “What started off as a mini PC running Home Assistant and Pi-hole has somehow escalated into a full-blown VLAN-separated network and self-hosting project. I currently use this setup for messing about with Windows Servers — Domain Controllers, SQL Servers, and cyber security type stuff.” Sound familiar? That snowball effect is exactly why you need automation before your homelab or prod environment becomes unmanageable.
WinRM Setup: The Part Everyone Gets Wrong
Before you write a single playbook, you need to get the communication channel working. WinRM is Microsoft’s remote management protocol, and Ansible talks to Windows through it. Default configuration? Locked down tighter than a drum. Secure, yes. Annoying as hell, also yes.
Quick Enablement (Dev/Test Only)
Run this PowerShell as Administrator on your Windows Server:
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
Restart-Service WinRM
Warning: Setting TrustedHosts to * in production is asking for trouble. We’ll cover Kerberos and HTTPS hardening later.
Test the Connection from Your Control Node
ansible windows -m win_ping -i inventory.ini
If you get pong, you’re in business. If you get unreachable, 99% of the time it’s a WinRM config issue.
The Three Most Common Faceplants
- WinRM service not running: Check with
Get-Service WinRM. - Firewall blocking ports 5985/5986:
New-NetFirewallRule -DisplayName "WinRM HTTP" -Direction Inbound -Protocol TCP -LocalPort 5985 -Action Allow. - Authentication method disabled:
Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true(dev only, please).
Production-Grade WinRM: Stop Running Naked
The quick-and-dirty config above is fine for your laptop. For production, you need HTTPS + Kerberos. Period.
Setting Up HTTPS WinRM
$cert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -DnsName "win-srv-01.example.com" -FriendlyName "WinRM HTTPS"
New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * -CertificateThumbprint $cert.Thumbprint -Force
Restart-Service WinRM
Then in your Ansible inventory:
[windows]
win-srv-01.example.com ansible_user=admin@EXAMPLE.COM ansible_password=your_pass ansible_connection=winrm ansible_winrm_server_cert_validation=ignore ansible_winrm_transport=kerberos ansible_port=5986
Key point: ansible_winrm_server_cert_validation=ignore is a necessary evil for self-signed certs. If you have an enterprise CA, get a proper certificate signed and switch to validate.
Kerberos vs. Basic: No Contest
Basic authentication sends credentials in plain text. Even over HTTPS, it’s vulnerable to man-in-the-middle attacks if someone’s got a foothold on the network. Kerberos handles ticket renewal automatically and is the gold standard in domain environments. It’s more work to set up—you need a Kerberos client on your control node and proper DNS resolution—but it’s worth it.
Your First Playbook: IIS on Windows Server
Enough theory. Here’s a playbook that installs IIS, starts the service, and deploys a static page.
---
- name: Setup IIS on Windows Server 2026
hosts: windows
gather_facts: yes
tasks:
- name: Install IIS Web-Server role
ansible.windows.win_feature:
name: Web-Server
state: present
include_management_tools: yes
- name: Ensure IIS service is running
ansible.windows.win_service:
name: W3Svc
state: started
start_mode: auto
- name: Create website directory
ansible.windows.win_file:
path: C:\inetpub\wwwroot\myapp
state: directory
- name: Deploy index.html
ansible.windows.win_copy:
src: files/index.html
dest: C:\inetpub\wwwroot\myapp\index.html
- name: Create IIS website
ansible.windows.win_iis_website:
name: MyApp
state: started
port: 80
ip: '*'
physical_path: C:\inetpub\wwwroot\myapp
Run it:
ansible-playbook -i inventory.ini setup-iis.yml
If everything works, hit http://win-srv-01 in your browser. If not, the WinRM debugging gauntlet awaits.
Module Selection: Don’t Write Linux Playbooks for Windows
This is the #1 mistake I see from newcomers. ansible.builtin.copy works great on Linux. On Windows, the path separators are different, the permission model is different, and the module doesn’t handle either correctly.
| Scenario | Linux Module | Windows Module |
|---|---|---|
| Install software | apt / yum | ansible.windows.win_feature (roles/features)ansible.windows.win_chocolatey (third-party packages) |
| File operations | ansible.builtin.copy | ansible.windows.win_copy |
| Service management | ansible.builtin.systemd | ansible.windows.win_service |
| Registry | N/A | ansible.windows.win_regedit |
| Execute command | ansible.builtin.shell / command | ansible.windows.win_shell / win_command |
Hard lesson learned: Don’t use win_shell to run complex PowerShell scripts unless there’s absolutely no module for what you need. Modules give you idempotency, proper error handling, and state tracking. win_shell gives you a shell script that may or may not work twice.
Advanced Techniques: Facts, Rolling Updates, and Vault
Gathering Windows Facts with the setup Module
ansible windows -m setup
This returns everything—OS version, memory, disk, network config, installed patches. Use it for conditional logic:
- name: Reboot only if required by pending updates
ansible.windows.win_reboot:
when: ansible_os_family == "Windows" and ansible_architecture == "64-bit"
Rolling Updates: Zero-Downtime Deployments
Say you have three Windows Servers behind a load balancer. You can’t take them all down at once. Use serial to roll through them one at a time:
- name: Rolling update of Windows web servers
hosts: windows_web
serial: 1
tasks:
- name: Take server out of load balancer pool
ansible.windows.win_shell: |
Invoke-RestMethod -Uri "http://loadbalancer/api/drain?server={{ inventory_hostname }}"
delegate_to: localhost
- name: Update application files
ansible.windows.win_copy:
src: app_v2/
dest: C:\MyApp\
- name: Restart application service
ansible.windows.win_service:
name: MyAppService
state: restarted
- name: Add server back to load balancer pool
ansible.windows.win_shell: |
Invoke-RestMethod -Uri "http://loadbalancer/api/enable?server={{ inventory_hostname }}"
delegate_to: localhost
Managing Secrets with Ansible Vault
Never put passwords in plaintext in your inventory. Use ansible-vault:
ansible-vault create group_vars/windows/vault.yml
Inside, store your credentials:
vault_ansible_password: "SuperSecretP@ssw0rd!"
Then reference it in your inventory:
[windows:vars]
ansible_password="{{ vault_ansible_password }}"
Run with --ask-vault-pass or set up a vault password file.
Best Practices Quick Reference
| Practice | Recommendation | Why |
|---|---|---|
| Authentication | Kerberos (domain) or CredSSP (non-domain) | Secure, supports double-hop |
| Transport | HTTPS (port 5986) | Encrypted, prevents MITM |
| Certificate | Enterprise CA-signed | Avoids ignore validation |
| Module selection | Prefer ansible.windows.* modules | Idempotency, better error handling |
| Fact gathering | Enable gather_facts: yes | Enables conditional logic |
| Secret management | Ansible Vault or CyberArk/Azure Key Vault | Never plaintext passwords |
| Testing | Docker or Vagrant with Windows containers | Fast feedback on playbook syntax |
| Error handling | Use ignore_errors and failed_when | Granular control over execution |
What the Community is Saying in 2026
Scrolling through Reddit and X, the sentiment on Ansible + Windows is split right down the middle.
The pro camp argues that Ansible’s declarative model is more intuitive than PowerShell DSC, and the learning curve is gentler. When your team has both Linux and Windows engineers, a single toolchain reduces fragmentation.
The con camp has a point: WinRM is brittle. It drops connections, debugging is painful, and the error messages are often useless. One r/devops user vented: “I spent more time debugging WinRM than actually writing the playbook. It’s 2026, why is this still a thing?”
My take: Both sides are right. WinRM is not SSH. But if you nail the HTTPS + Kerberos setup, it’s stable enough for daily use. The real pain point is the module ecosystem—it’s nowhere near as rich as Linux. You’ll struggle to find a well-maintained community module for win_nginx or win_docker. More often than not, you’ll fall back to win_shell to call PowerShell directly, which brings you back to the “scattered scripts” problem Ansible was supposed to solve.
Final Thoughts
Ansible + Windows Server in 2026 isn’t a “sweet spot” combination—it’s a pragmatic compromise. If you’re dealing with Windows legacy systems (AD, Exchange, SQL Server), Ansible is probably the least bad option for unified automation.
My advice: start small. Use Ansible for patch management or service restarts—low-risk operations that build your team’s confidence. Once you’ve got the WinRM kinks worked out, expand to application deployment and configuration management. Don’t try to automate your entire datacenter in week one. You’ll drown in WinRM error messages.
And if you get stuck, hit up r/ansible or r/homelab on Reddit. Chances are, someone’s already faceplanted into the exact same issue.
Frequently Asked Questions (FAQ)
Q: WinRM keeps disconnecting. What do I do?
Check network stability, firewall rules, and WinRM timeout settings. Increase ansible_winrm_operation_timeout_sec and ansible_winrm_read_timeout_sec in your inventory.
Q: Can I use Ansible to manage Windows without a domain?
Yes. Use HTTPS + self-signed certificates + Basic authentication, but this is not recommended for production. Consider CredSSP or NTLM as alternatives.
Q: Does Ansible work with Windows 10/11 desktop editions?
Yes, Pro and Enterprise editions support WinRM. However, Microsoft recommends using Windows Server for management nodes.
Q: How do I debug Ansible Windows modules?
Add -vvvv to your ansible-playbook command for verbose logging. On the Windows side, check WinRM operational logs: Get-WinEvent -LogName Microsoft-Windows-WinRM/Operational.
Q: PowerShell DSC vs. Ansible—which is better?
DSC is more native for Windows configuration management. Ansible wins on cross-platform uniformity and community ecosystem. Pure Windows shop? Consider DSC. Mixed environment? Go Ansible.