Ansible + Windows Overview

Ansible manages Windows hosts using WinRM (Windows Remote Management) or PSRP (PowerShell Remoting Protocol) instead of SSH. The control node still runs on Linux/macOS.

Step 1: Prepare the Windows Host

Run this PowerShell script on each Windows host (as Administrator):

# Enable WinRM
winrm quickconfig -force

# Set up HTTPS listener (recommended) or HTTP
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
winrm set winrm/config/service/auth '@{Basic="true"}'

# Increase memory limit for large operations
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}'

# Configure firewall
netsh advfirewall firewall add rule name="WinRM HTTP" dir=in localport=5985 protocol=tcp action=allow
netsh advfirewall firewall add rule name="WinRM HTTPS" dir=in localport=5986 protocol=tcp action=allow

Or use the official Ansible setup script:

# Download and run the ConfigureRemotingForAnsible script
$url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
$file = "$env:temp\ConfigureRemotingForAnsible.ps1"
(New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
powershell.exe -ExecutionPolicy ByPass -File $file

Fix: LocalAccountTokenFilterPolicy

If you get authentication errors with local admin accounts:

# Required for non-domain-joined hosts
New-ItemProperty -Name LocalAccountTokenFilterPolicy `
  -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System `
  -PropertyType DWord -Value 1 -Force

Fix: Network Connection Type

If you see "WinRM firewall exception will not work since one of the network connection types on this machine is set to public":

# Change network profile to Private
Set-NetConnectionProfile -InterfaceIndex (Get-NetConnectionProfile).InterfaceIndex -NetworkCategory Private

Step 2: Configure Ansible Inventory

[windows]
win1 ansible_host=192.168.1.50
win2 ansible_host=192.168.1.51

[windows:vars]
ansible_user=Administrator
ansible_password={{ vault_win_password }}
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
ansible_winrm_transport=ntlm
ansible_port=5986

Install pywinrm on Control Node

pip install pywinrm

Step 3: Test Connectivity

ansible windows -m ansible.windows.win_ping

Expected output:

win1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Common Windows Modules

Copy Files (win_copy)

- name: Copy file to Windows
  ansible.windows.win_copy:
    src: files/app.config
    dest: C:\App\config\app.config

- name: Copy with content
  ansible.windows.win_copy:
    content: |
      [Settings]
      LogLevel=Info
      Port=8080
    dest: C:\App\settings.ini

Manage Services (win_service)

- name: Start a Windows service
  ansible.windows.win_service:
    name: wuauserv
    state: started
    start_mode: auto

- name: Stop and disable a service
  ansible.windows.win_service:
    name: Spooler
    state: stopped
    start_mode: disabled

Install Software with Chocolatey

- name: Install Chocolatey packages
  chocolatey.chocolatey.win_chocolatey:
    name: "{{ item }}"
    state: present
  loop:
    - googlechrome
    - notepadplusplus
    - 7zip
    - git
    - vscode

Run PowerShell Commands

- name: Run PowerShell script
  ansible.windows.win_powershell:
    script: |
      Get-Process | Where-Object { $_.CPU -gt 100 } | 
        Select-Object Name, CPU | 
        ConvertTo-Json
  register: ps_result

- name: Show result
  ansible.builtin.debug:
    msg: "{{ ps_result.output }}"

Manage Windows Features

- name: Install IIS
  ansible.windows.win_feature:
    name: Web-Server
    state: present
    include_management_tools: true

Windows Reboot

- name: Reboot and wait
  ansible.windows.win_reboot:
    reboot_timeout: 600
    post_reboot_delay: 60
    msg: "Ansible is rebooting this server"

Manage Files and Directories

- name: Create directory
  ansible.windows.win_file:
    path: C:\App\logs
    state: directory

- name: Delete a file
  ansible.windows.win_file:
    path: C:\Temp\old-installer.exe
    state: absent

Download Files

- name: Download installer
  ansible.windows.win_get_url:
    url: https://example.com/installer.msi
    dest: C:\Temp\installer.msi
    checksum: abc123def456
    checksum_algorithm: sha256

WinRM vs PSRP

FeatureWinRMPSRP
ProtocolHTTP/HTTPSPowerShell Remoting
Port5985/59865985/5986
PerformanceGoodBetter for large payloads
SetupStandardRequires pypsrp

To use PSRP:

pip install pypsrp
[windows:vars]
ansible_connection=psrp
ansible_psrp_auth=ntlm

Troubleshooting

"winrm or requests is not installed"

pip install pywinrm requests

Connection timeout

# Increase timeout in ansible.cfg
[defaults]
timeout = 60

Certificate validation error

ansible_winrm_server_cert_validation=ignore

Explore our Windows automation tutorials and 800+ Ansible examples.