AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible WinRM: Configure Windows Remote Management Connection (Complete Guide)

By Luca Berton · Published 2024-01-01 · Category: installation

How to configure WinRM for Ansible Windows automation. Set up WinRM HTTPS, authentication methods, pywinrm, troubleshoot connection errors.

Ansible + Windows: How It Works

Ansible manages Windows machines over WinRM (Windows Remote Management) instead of SSH. No agent is installed on Windows — Ansible sends PowerShell commands over WinRM and collects results.

┌──────────────┐    WinRM/HTTPS     ┌──────────────┐
│   Control     │ ──────────────────▶│   Windows     │
│   Node        │   (port 5986)      │   Server      │
│   (Linux)     │                    │               │
└──────────────┘                    └──────────────┘
   Ansible + pywinrm                  WinRM enabled

Requirements: • Control node: Linux or macOS (Ansible doesn't run on Windows as control node) • Managed nodes: Windows Server 2016+ or Windows 10+ • Python package: pywinrm • WinRM enabled on Windows hosts

See also: AAP 2.6 Windows Automation: WinRM, PowerShell, and Active Directory Management

Enable WinRM on Windows

PowerShell Script (Recommended)

# Run as Administrator on each Windows host
# Download and run the Ansible WinRM setup script
$url = "https://raw.githubusercontent.com/ansible/ansible-documentation/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

Manual Setup

# Enable WinRM
Enable-PSRemoting -Force

# Set up HTTPS listener (recommended for production) $cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation Cert:\LocalMachine\My winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"$env:COMPUTERNAME`";CertificateThumbprint=`"$($cert.Thumbprint)`"}"

# Allow basic auth (for testing only) winrm set winrm/config/service/auth '@{Basic="true"}'

# Allow unencrypted (NEVER in production) # winrm set winrm/config/service '@{AllowUnencrypted="true"}'

# Set execution policy Set-ExecutionPolicy RemoteSigned -Force

# Configure firewall New-NetFirewallRule -Name "WinRM-HTTPS" -DisplayName "WinRM over HTTPS" -Enabled True -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow

Enable WinRM via Group Policy (Domain)

Computer Configuration → Administrative Templates → Windows Components → Windows Remote Management → WinRM Service
  → Allow remote server management through WinRM → Enabled
  → IPv4 filter: * (or specific subnets)

Inventory for Windows

# inventory/windows.yml
all:
  children:
    windows:
      children:
        web_servers:
          hosts:
            web-win-01:
              ansible_host: 10.0.1.10
            web-win-02:
              ansible_host: 10.0.1.11
        domain_controllers:
          hosts:
            dc-01:
              ansible_host: 10.0.0.1
            dc-02:
              ansible_host: 10.0.0.2
        sql_servers:
          hosts:
            sql-01:
              ansible_host: 10.0.2.10
      vars:
        ansible_connection: winrm
        ansible_winrm_transport: ntlm
        ansible_winrm_server_cert_validation: ignore
        ansible_port: 5986
        ansible_winrm_scheme: https
        ansible_user: "{{ vault_win_user }}"
        ansible_password: "{{ vault_win_password }}"

Kerberos Authentication (Domain-Joined)

# ansible.cfg
[defaults]
# Kerberos requires: pip install pywinrm[kerberos]

# inventory vars: # ansible_winrm_transport: kerberos # ansible_user: ansible@COMPANY.COM # ansible_password: vault_password

# Install Kerberos support
pip install pywinrm[kerberos]

# Configure /etc/krb5.conf # [realms] # COMPANY.COM = { # kdc = dc-01.company.com # admin_server = dc-01.company.com # }

See also: Ansible Windows Server 2025 Automation: WinRM, PSRP, Active Directory, IIS, Hyper-V Complete Guide

Windows Features and Roles

---
- name: Configure Windows Server roles
  hosts: web_servers
  tasks:
    - name: Install IIS
      ansible.windows.win_feature:
        name:
          - Web-Server
          - Web-Asp-Net45
          - Web-Mgmt-Console
          - Web-Scripting-Tools
        state: present
        include_management_tools: true
      register: iis_install

- name: Reboot if required ansible.windows.win_reboot: reboot_timeout: 600 when: iis_install.reboot_required

- name: Install .NET Framework 4.8 ansible.windows.win_feature: name: NET-Framework-45-Features state: present include_sub_features: true

- name: Remove unnecessary features ansible.windows.win_feature: name: - Telnet-Client - TFTP-Client state: absent

IIS Web Server Management

---
- name: Configure IIS
  hosts: web_servers
  tasks:
    - name: Create application pool
      community.windows.win_iis_webapppool:
        name: MyAppPool
        state: started
        attributes:
          managedRuntimeVersion: v4.0
          managedPipelineMode: Integrated
          startMode: AlwaysRunning
          processModel.identityType: ApplicationPoolIdentity
          processModel.idleTimeout: "00:00:00"
          recycling.periodicRestart.time: "00:00:00"

- name: Create website community.windows.win_iis_website: name: MyWebApp state: started port: 443 ssl: true ip: "*" hostname: app.company.com physical_path: C:\inetpub\myapp application_pool: MyAppPool parameters: | logFile.directory:C:\logs\iis

- name: Create virtual directory community.windows.win_iis_virtualdirectory: name: api site: MyWebApp physical_path: C:\inetpub\myapp\api state: present

- name: Deploy application files ansible.windows.win_copy: src: app/ dest: C:\inetpub\myapp\ force: true notify: restart iis app pool

handlers: - name: restart iis app pool community.windows.win_iis_webapppool: name: MyAppPool state: restarted

See also: Ansible for Windows Server Enterprise Management: Active Directory, IIS, and Group Policy

Software Installation

---
- name: Install software on Windows
  hosts: windows
  tasks:
    # Chocolatey packages
    - name: Install Chocolatey
      chocolatey.chocolatey.win_chocolatey:
        name: chocolatey
        state: present

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

# MSI packages - name: Install application from MSI ansible.windows.win_package: path: https://download.company.com/app-2.0.msi product_id: '{12345678-1234-1234-1234-123456789012}' arguments: /quiet /norestart INSTALLDIR=C:\App state: present

# EXE installers - name: Install agent ansible.windows.win_package: path: C:\temp\agent-setup.exe arguments: /S /v"/qn SERVERIP=10.0.0.100" expected_return_code: [0, 3010] state: present

Active Directory

ansible-galaxy collection install microsoft.ad
---
- name: Manage Active Directory
  hosts: domain_controllers
  tasks:
    - name: Create OU structure
      microsoft.ad.ou:
        name: "{{ item.name }}"
        path: "{{ item.path }}"
        state: present
        protected: true
      loop:
        - { name: "Company", path: "DC=company,DC=com" }
        - { name: "Users", path: "OU=Company,DC=company,DC=com" }
        - { name: "Groups", path: "OU=Company,DC=company,DC=com" }
        - { name: "Servers", path: "OU=Company,DC=company,DC=com" }
        - { name: "Workstations", path: "OU=Company,DC=company,DC=com" }

- name: Create AD users microsoft.ad.user: name: "{{ item.username }}" firstname: "{{ item.first }}" surname: "{{ item.last }}" password: "{{ item.password }}" state: present path: "OU=Users,OU=Company,DC=company,DC=com" email: "{{ item.username }}@company.com" groups: add: - Domain Users - "{{ item.department }}" update_password: on_create loop: "{{ ad_users }}" no_log: true

- name: Create security groups microsoft.ad.group: name: "{{ item }}" scope: global category: security path: "OU=Groups,OU=Company,DC=company,DC=com" state: present loop: - IT-Admins - Developers - Finance - HR

- name: Join computer to domain microsoft.ad.membership: dns_domain_name: company.com domain_admin_user: "{{ vault_domain_admin }}" domain_admin_password: "{{ vault_domain_password }}" domain_ou_path: "OU=Servers,OU=Company,DC=company,DC=com" state: domain reboot: true

Windows Services

    - name: Configure services
      ansible.windows.win_service:
        name: "{{ item.name }}"
        start_mode: "{{ item.start_mode }}"
        state: "{{ item.state }}"
      loop:
        - { name: wuauserv, start_mode: auto, state: started }       # Windows Update
        - { name: W3SVC, start_mode: auto, state: started }          # IIS
        - { name: Spooler, start_mode: disabled, state: stopped }    # Print Spooler (security)
        - { name: RemoteRegistry, start_mode: disabled, state: stopped }

- name: Create custom Windows service ansible.windows.win_service: name: MyAppService path: C:\App\myapp.exe --service display_name: "My Application Service" description: "Custom application service" start_mode: auto state: started username: .\svc_myapp password: "{{ vault_svc_password }}" dependencies: - LanmanServer - MSSQLSERVER

Registry Management

    - name: Configure registry settings
      ansible.windows.win_regedit:
        path: "{{ item.path }}"
        name: "{{ item.name }}"
        data: "{{ item.data }}"
        type: "{{ item.type }}"
      loop:
        # Disable SMBv1
        - path: HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
          name: SMB1
          data: 0
          type: dword
        # Enable audit policy
        - path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit
          name: ProcessCreationIncludeCmdLine_Enabled
          data: 1
          type: dword
        # Set RDP timeout
        - path: HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
          name: MaxIdleTime
          data: 900000
          type: dword

Windows Updates

---
- name: Patch Windows servers
  hosts: windows
  serial: 2    # Patch 2 at a time

tasks: - name: Install security updates ansible.windows.win_updates: category_names: - SecurityUpdates - CriticalUpdates state: installed reboot: true reboot_timeout: 1800 register: update_result

- name: Report installed updates ansible.builtin.debug: msg: "Installed {{ update_result.installed_update_count }} updates on {{ inventory_hostname }}" when: update_result.installed_update_count > 0

PowerShell Execution

    - name: Run PowerShell script
      ansible.windows.win_powershell:
        script: |
          $services = Get-Service | Where-Object { $_.Status -eq 'Running' }
          $services | Select-Object Name, DisplayName, StartType |
            ConvertTo-Json
      register: ps_result

- name: Run PowerShell with parameters ansible.windows.win_powershell: script: | param($Path, $Days) Get-ChildItem -Path $Path -Recurse | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$Days) } | Remove-Item -Force parameters: Path: C:\Logs Days: 30

Security Hardening

---
- name: Windows security hardening
  hosts: windows
  tasks:
    - name: Set password policy
      ansible.windows.win_security_policy:
        section: System Access
        key: "{{ item.key }}"
        value: "{{ item.value }}"
      loop:
        - { key: MinimumPasswordLength, value: 14 }
        - { key: PasswordComplexity, value: 1 }
        - { key: MaximumPasswordAge, value: 90 }
        - { key: LockoutBadCount, value: 5 }

- name: Disable unnecessary features ansible.windows.win_feature: name: - Telnet-Client - TFTP-Client - SMB1Protocol state: absent

- name: Configure Windows Firewall community.windows.win_firewall_rule: name: "Block Telnet Inbound" localport: 23 protocol: tcp direction: in action: block enabled: true state: present

- name: Enable Windows Defender ansible.windows.win_powershell: script: | Set-MpPreference -DisableRealtimeMonitoring $false Set-MpPreference -MAPSReporting Advanced Update-MpSignature

FAQ

Can Ansible run on Windows as a control node?

No. The Ansible control node must be Linux or macOS. You can manage Windows from Linux using WinRM. If you only have Windows, use WSL2 (Windows Subsystem for Linux) to run Ansible.

WinRM or SSH for Windows?

WinRM is the standard and best-supported connection method. Windows 10+ includes OpenSSH Server, and Ansible can use ansible_connection: ssh with it. However, WinRM provides better integration with Windows authentication (NTLM, Kerberos, CredSSP). Use WinRM unless you have specific SSH requirements.

How do I handle reboots?

Use ansible.windows.win_reboot after tasks that require reboot (Windows Updates, feature installation). Set appropriate reboot_timeout for long updates. Check reboot_required in task results to conditionally reboot.

What about Windows containers?

Ansible manages Windows containers with community.docker collection over WinRM. Docker Desktop or Docker EE on Windows Server works with the same docker_container module.

Conclusion

Ansible automates Windows at scale — IIS, Active Directory, Windows features, software deployment, security hardening, and patch management. Configure WinRM once, and you manage Windows the same way you manage Linux: declarative YAML playbooks, idempotent operations, version-controlled infrastructure. Use Kerberos for domain environments, Chocolatey for package management, and serial for safe rolling updates.

Related Articles

Ansible vs Puppet vs Chef ComparisonAnsible for Cisco Network AutomationAAP 2.6 Architecture and ComponentsInstall Ansible Complete GuideAnsible Dynamic Inventory Complete Guide

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home