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.

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

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

Automate Windows infrastructure with AAP 2.6. Configure WinRM connectivity, run PowerShell scripts, manage Active Directory, deploy IIS, handle Windows.

Windows Automation in AAP 2.6

AAP 2.6 provides full Windows automation support through WinRM (Windows Remote Management) and SSH. You can manage Windows servers, workstations, and Active Directory environments using the same platform that handles Linux infrastructure.

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

Prerequisites

Windows Host Requirements

RequirementDetails
PowerShell5.1 or later
.NET Framework4.6 or later
WinRMEnabled and configured
OSWindows Server 2016+ or Windows 10/11

Enable WinRM on Windows Hosts

Run this PowerShell script on target Windows hosts:

# Enable WinRM with HTTPS
$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation Cert:\LocalMachine\My
$thumbprint = $cert.Thumbprint

winrm quickconfig -quiet
winrm set winrm/config/service/auth '@{Basic="true"}'
winrm set winrm/config/service '@{AllowUnencrypted="false"}'

# Create HTTPS listener
winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"$env:COMPUTERNAME`";CertificateThumbprint=`"$thumbprint`"}"

# Firewall rule
New-NetFirewallRule -Name "WinRM-HTTPS" -DisplayName "WinRM HTTPS" -Enabled True -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow

Or use the Ansible-provided ConfigureRemotingForAnsible.ps1 script:

Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile ConfigureRemotingForAnsible.ps1
.\ConfigureRemotingForAnsible.ps1 -EnableCredSSP -ForceNewSSLCert

Credential Configuration

Machine Credential for Windows

- name: Create Windows machine credential
  ansible.platform.credential:
    controller_host: "{{ gateway_url }}"
    controller_username: "{{ controller_user }}"
    controller_password: "{{ controller_pass }}"
    name: "Windows Domain Admin"
    organization: "Operations"
    credential_type: "Machine"
    inputs:
      username: "DOMAIN\\ansible_svc"
      password: "{{ vault_windows_password }}"
    state: present

Inventory Variables for WinRM

# Group variables for Windows hosts
- name: Create Windows group
  ansible.platform.group:
    controller_host: "{{ gateway_url }}"
    controller_username: "{{ controller_user }}"
    controller_password: "{{ controller_pass }}"
    name: "windows"
    inventory: "Production Windows"
    variables:
      ansible_connection: winrm
      ansible_winrm_transport: ntlm
      ansible_winrm_server_cert_validation: ignore
      ansible_port: 5986
      ansible_winrm_scheme: https
    state: present

Connection Methods

TransportAuth MethodUse Case
ntlmNTLMDomain and local accounts
kerberosKerberosDomain environments (most secure)
credsspCredSSPDouble-hop scenarios
basicBasic authLocal accounts over HTTPS
certificateClient certCertificate-based auth

Kerberos Configuration

For domain environments, Kerberos is recommended:

# Execution Environment with Kerberos support
---
version: 3
images:
  base_image:
    name: registry.redhat.io/ansible-automation-platform-26/ee-supported-rhel9:latest
dependencies:
  python:
    - pywinrm>=0.4.0
    - requests-kerberos>=0.14
    - pykerberos>=1.2
  system:
    - krb5-workstation [platform:rpm]
    - krb5-libs [platform:rpm]
    - krb5-devel [platform:rpm]
additional_build_steps:
  append_final:
    - COPY krb5.conf /etc/krb5.conf
# krb5.conf for the EE
[libdefaults]
default_realm = EXAMPLE.COM
dns_lookup_realm = false
dns_lookup_kdc = true

[realms]
EXAMPLE.COM = {
    kdc = dc01.example.com
    admin_server = dc01.example.com
}

[domain_realm]
.example.com = EXAMPLE.COM
example.com = EXAMPLE.COM

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

Common Windows Automation Tasks

Install Windows Features and Roles

- name: Install IIS web server
  hosts: windows_webservers
  tasks:
    - name: Install IIS with management tools
      ansible.windows.win_feature:
        name:
          - Web-Server
          - Web-Mgmt-Tools
          - Web-Asp-Net45
          - Web-Net-Ext45
        state: present
        include_management_tools: true
      register: iis_install

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

Manage Windows Services

- name: Manage Windows services
  hosts: windows
  tasks:
    - name: Ensure critical services are running
      ansible.windows.win_service:
        name: "{{ item }}"
        start_mode: auto
        state: started
      loop:
        - W32Time
        - WinRM
        - Winmgmt
        - EventLog

    - name: Disable unnecessary services
      ansible.windows.win_service:
        name: "{{ item }}"
        start_mode: disabled
        state: stopped
      loop:
        - RemoteRegistry
        - TlntSvr

Windows Updates

- name: Apply Windows updates
  hosts: windows
  tasks:
    - name: Install all critical and security updates
      ansible.windows.win_updates:
        category_names:
          - CriticalUpdates
          - SecurityUpdates
        state: installed
        reboot: true
        reboot_timeout: 3600
      register: update_result

    - name: Report update status
      ansible.builtin.debug:
        msg: |
          Updates installed: {{ update_result.installed_update_count }}
          Reboot required: {{ update_result.reboot_required }}
          Updates: {{ update_result.updates | map(attribute='title') | list }}

Active Directory Management

- name: Manage Active Directory
  hosts: domain_controllers
  tasks:
    - name: Create organizational unit
      microsoft.ad.ou:
        name: "Automation Managed"
        path: "DC=example,DC=com"
        state: present

    - name: Create service account
      microsoft.ad.user:
        name: "svc_ansible"
        firstname: "Ansible"
        surname: "Service Account"
        password: "{{ vault_svc_password }}"
        path: "OU=Service Accounts,DC=example,DC=com"
        password_never_expires: true
        user_cannot_change_password: true
        state: present

    - name: Create security group
      microsoft.ad.group:
        name: "Ansible Managed Servers"
        path: "OU=Security Groups,DC=example,DC=com"
        scope: global
        category: security
        members:
          add:
            - "svc_ansible"
        state: present

    - name: Add computer to group
      microsoft.ad.group:
        name: "Ansible Managed Servers"
        members:
          add:
            - "WEB01$"
            - "WEB02$"
            - "APP01$"

Group Policy Management

- name: Configure Group Policy settings via registry
  hosts: windows
  tasks:
    - name: Set audit policy
      ansible.windows.win_regedit:
        path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit
        name: ProcessCreationIncludeCmdLine_Enabled
        data: 1
        type: dword

    - name: Configure Windows Firewall
      community.windows.win_firewall:
        state: enabled
        profiles:
          - Domain
          - Private
          - Public

Deploy IIS Website

- name: Deploy IIS website
  hosts: windows_webservers
  tasks:
    - name: Create website directory
      ansible.windows.win_file:
        path: C:\inetpub\myapp
        state: directory

    - name: Deploy application files
      ansible.windows.win_copy:
        src: files/myapp/
        dest: C:\inetpub\myapp\

    - name: Create IIS application pool
      community.windows.win_iis_webapppool:
        name: MyAppPool
        state: started
        attributes:
          managedRuntimeVersion: v4.0
          autoStart: true
          startMode: AlwaysRunning

    - name: Create IIS website
      community.windows.win_iis_website:
        name: MyApp
        state: started
        port: 443
        ssl: true
        physical_path: C:\inetpub\myapp
        application_pool: MyAppPool
        parameters: "logFile.directory:C:\\Logs\\MyApp"

PowerShell Script Execution

- name: Run PowerShell scripts
  hosts: windows
  tasks:
    - name: Execute inline PowerShell
      ansible.windows.win_powershell:
        script: |
          $services = Get-Service | Where-Object { $_.Status -eq 'Stopped' -and $_.StartType -eq 'Automatic' }
          $services | ForEach-Object {
              Write-Output "Starting $($_.Name)..."
              Start-Service $_.Name -ErrorAction SilentlyContinue
          }
          $Ansible.Result = @{
              started = ($services | Measure-Object).Count
          }
      register: ps_result

    - name: Show result
      ansible.builtin.debug:
        msg: "Started {{ ps_result.result.started }} services"

    - name: Run script file
      ansible.windows.win_powershell:
        script: "{{ lookup('file', 'scripts/health-check.ps1') }}"
        parameters:
          Verbose: true
          OutputPath: C:\Reports\health-check.html

Windows Certificate Management

- name: Manage certificates
  hosts: windows
  tasks:
    - name: Import PFX certificate
      ansible.windows.win_certificate_store:
        path: C:\certs\webapp.pfx
        password: "{{ cert_password }}"
        store_location: LocalMachine
        store_name: My
        state: present

    - name: Find expiring certificates
      ansible.windows.win_powershell:
        script: |
          $threshold = (Get-Date).AddDays(30)
          $expiring = Get-ChildItem Cert:\LocalMachine\My |
            Where-Object { $_.NotAfter -lt $threshold }
          $Ansible.Result = $expiring | Select-Object Subject, NotAfter, Thumbprint
      register: expiring_certs

    - name: Alert on expiring certs
      ansible.builtin.debug:
        msg: "WARNING: {{ item.Subject }} expires {{ item.NotAfter }}"
      loop: "{{ expiring_certs.result }}"
      when: expiring_certs.result | length > 0

Execution Environment for Windows

Build a dedicated EE with Windows dependencies:

---
version: 3
images:
  base_image:
    name: registry.redhat.io/ansible-automation-platform-26/ee-minimal-rhel9:latest
dependencies:
  galaxy:
    collections:
      - name: ansible.windows
        version: ">=2.5.0"
      - name: community.windows
        version: ">=2.3.0"
      - name: microsoft.ad
        version: ">=1.7.0"
      - name: chocolatey.chocolatey
        version: ">=1.5.0"
  python:
    - pywinrm>=0.4.0
    - requests-ntlm>=1.2
    - requests-kerberos>=0.14
    - pykerberos>=1.2
  system:
    - krb5-workstation [platform:rpm]
    - krb5-libs [platform:rpm]

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

FAQ

Should I use WinRM or SSH for Windows?

WinRM is the standard and best-supported method. Windows OpenSSH works but has limitations: no become, no win_* modules (only shell/raw). Use WinRM for production Windows automation.

How do I handle the double-hop problem?

When connecting to a Windows host and needing to access a network resource (like a file share), you hit the double-hop problem. Use CredSSP transport (ansible_winrm_transport: credssp) or Kerberos delegation to resolve this.

Can I manage Windows hosts from Linux execution nodes?

Yes. The EE runs on Linux and connects to Windows hosts via WinRM over the network. No Windows software is needed on the execution node — just the Python pywinrm library (included in the EE).

How do I run domain join operations?

Use the microsoft.ad.membership module. The credential must have domain join permissions, and the WinRM connection must use Kerberos or NTLM with a domain account.

What about Windows Nano Server or Server Core?

Both are supported via WinRM. Server Core works identically to full installations. Nano Server has limited PowerShell support, so test modules before deploying.

Conclusion

AAP 2.6 treats Windows as a first-class automation target. From Active Directory management to IIS deployments, Windows Updates to PowerShell scripting, the platform provides comprehensive Windows automation capabilities alongside Linux. Build a dedicated Windows EE, configure WinRM with Kerberos for enterprise environments, and automate your entire Windows estate through the same platform.

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home