Introduction to Ansible for Windows Server 2019

Ansible is an open-source IT automation platform developed by Red Hat that enables infrastructure as code for provisioning, configuration management, application deployment, and orchestration. While Ansible was originally designed for Linux management using SSH, it fully supports Windows Server 2019 management using WinRM (Windows Remote Management) as the transport. Ansible for Windows uses PowerShell natively, giving access to the full power of Windows management without installing agents on managed nodes. The Ansible control node where Ansible itself is installed must run on Linux or macOS. Ansible is agentless by design, and Windows Server 2019 only requires WinRM to be enabled and configured. This makes Ansible an excellent choice for automating Windows server configuration alongside Linux systems in heterogeneous environments.

Setting Up the Ansible Control Node

Install Ansible on a Linux control node such as Ubuntu 22.04. The control node manages Windows Server 2019 targets via WinRM. Install Ansible and required Python packages:

sudo apt-get update && sudo apt-get install -y python3-pip python3-dev
pip3 install ansible pywinrm kerberos requests-kerberos
ansible --version

Install the community.windows and ansible.windows Ansible Galaxy collections which provide Windows-specific modules:

ansible-galaxy collection install ansible.windows
ansible-galaxy collection install community.windows
ansible-galaxy collection install microsoft.ad

Preparing Windows Server 2019 for Ansible

Windows Server 2019 must have WinRM configured to accept Ansible connections. Ansible provides a configuration script that sets up WinRM with the correct settings. Run this from an elevated PowerShell session on the Windows Server 2019 machine:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
$file = "$env:TEMPConfigureRemotingForAnsible.ps1"
Invoke-WebRequest -Uri $url -OutFile $file
& $file -EnableCredSSP -DisableBasicAuth -SkipNetworkProfileCheck

Alternatively, manually configure WinRM for HTTPS with a self-signed certificate:

Enable-PSRemoting -Force
$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation Cert:LocalMachineMy
New-Item -Path WSMan:localhostListener -Transport HTTPS -Address * -CertificateThumbprint $cert.Thumbprint -Force
Set-Item WSMan:localhostServiceAuthBasic -Value $true
Set-Item WSMan:localhostServiceAllowUnencrypted -Value $false
New-NetFirewallRule -DisplayName "WinRM HTTPS Ansible" -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow

Verify WinRM is listening on the correct ports:

winrm enumerate winrm/config/Listener
netstat -ano | findstr "5985|5986"

Creating the Ansible Inventory

The inventory file defines which hosts Ansible manages and how to connect to them. Create an inventory for Windows Server 2019 machines. Create /etc/ansible/hosts or a project-specific inventory file:

[windows_servers]
ws2019-01.contoso.com
ws2019-02.contoso.com
ws2019-03.contoso.com

[windows_servers:vars]
ansible_user=Administrator
ansible_password=AdminP@ssw0rd123
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_winrm_server_cert_validation=ignore
ansible_winrm_port=5986
ansible_winrm_scheme=https
ansible_become=false

For Kerberos authentication (recommended in domain environments), use:

[windows_servers:vars]
[email protected]
ansible_password=AnsibleSvc@123!
ansible_connection=winrm
ansible_winrm_transport=kerberos
ansible_winrm_server_cert_validation=ignore
ansible_winrm_kerberos_delegation=true

Testing Ansible Connectivity

Test connectivity from the Ansible control node to Windows Server 2019 using the win_ping module:

ansible windows_servers -m win_ping
ansible ws2019-01.contoso.com -m win_ping -i inventory.ini
ansible windows_servers -m win_command -a "whoami" -i inventory.ini
ansible windows_servers -m win_shell -a "Get-Service | Where-Object {$_.Status -eq 'Stopped' -and $_.StartType -eq 'Automatic'}" -i inventory.ini

Gather facts about Windows Server 2019 machines:

ansible ws2019-01.contoso.com -m setup -i inventory.ini | head -100
ansible windows_servers -m win_gather_facts -i inventory.ini

Writing Ansible Playbooks for Windows Server 2019

Ansible playbooks are YAML files that define automation tasks. Create a playbook to configure Windows Server 2019 security settings:

---
- name: Configure Windows Server 2019 Security Baseline
  hosts: windows_servers
  gather_facts: true
  tasks:
    - name: Disable SMBv1
      ansible.windows.win_feature:
        name: FS-SMB1
        state: absent

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

    - name: Set password policy
      community.windows.win_security_policy:
        section: System Access
        key: MinimumPasswordLength
        value: 14

    - name: Configure Windows Update
      community.windows.win_updates:
        category_names:
          - CriticalUpdates
          - SecurityUpdates
        state: installed
        reboot: false

    - name: Enable RDP with NLA
      ansible.windows.win_reg_entry:
        path: HKLM:SystemCurrentControlSetControlTerminal ServerWinStationsRDP-Tcp
        name: UserAuthentication
        data: 1
        type: dword

    - name: Disable AutoRun
      ansible.windows.win_reg_entry:
        path: HKLM:SOFTWAREMicrosoftWindowsCurrentVersionPoliciesExplorer
        name: NoDriveTypeAutoRun
        data: 255
        type: dword

Run the playbook:

ansible-playbook -i inventory.ini windows_security_baseline.yml
ansible-playbook -i inventory.ini windows_security_baseline.yml --check  # Dry run
ansible-playbook -i inventory.ini windows_security_baseline.yml --diff   # Show changes

Managing Windows Features and Roles with Ansible

Install and remove Windows Server roles and features using the win_feature module. Create a playbook for a web server role configuration:

---
- name: Configure IIS Web Server
  hosts: web_servers
  tasks:
    - name: Install IIS
      ansible.windows.win_feature:
        name:
          - Web-Server
          - Web-Asp-Net45
          - Web-Windows-Auth
          - Web-Common-Http
          - Web-Default-Doc
          - Web-Http-Logging
        state: present
        include_management_tools: true
      register: iis_install

    - name: Reboot if IIS installation requires it
      ansible.windows.win_reboot:
      when: iis_install.reboot_required

    - name: Create web application directory
      ansible.windows.win_file:
        path: C:inetpubwwwrootMyApp
        state: directory

    - name: Copy web application files
      ansible.windows.win_copy:
        src: files/webapp/
        dest: C:inetpubwwwrootMyApp

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

    - name: Create IIS website
      community.windows.win_iis_website:
        name: MyWebSite
        state: started
        port: 443
        ip: "*"
        application_pool: MyAppPool
        physical_path: C:inetpubwwwrootMyApp

Patching Windows Server 2019 with Ansible

Use the win_updates module to automate patch management across Windows Server 2019 machines. Create a patching playbook with pre and post-patch health checks:

---
- name: Patch Windows Server 2019
  hosts: windows_servers
  serial: 1
  tasks:
    - name: Check disk space before patching
      ansible.windows.win_shell: |
        $disk = Get-PSDrive C
        $freeGB = [math]::Round($disk.Free/1GB, 2)
        if ($freeGB -lt 10) { Write-Error "Insufficient disk space: ${freeGB}GB free" }
        Write-Output "Free disk space: ${freeGB}GB"

    - name: Install critical and security updates
      ansible.windows.win_updates:
        category_names:
          - CriticalUpdates
          - SecurityUpdates
          - UpdateRollups
        state: installed
        reboot: false
      register: update_result

    - name: Display update summary
      ansible.builtin.debug:
        msg: "Installed {{ update_result.installed_update_count }} updates"

    - name: Reboot if updates require it
      ansible.windows.win_reboot:
        reboot_timeout: 600
        post_reboot_delay: 60
      when: update_result.reboot_required

    - name: Verify server is responsive after reboot
      ansible.windows.win_ping:

Run the patching playbook with controlled serial execution:

ansible-playbook -i inventory.ini patch_windows.yml --limit ws2019-01.contoso.com
ansible-playbook -i inventory.ini patch_windows.yml --tags "security" --forks 1

Using Ansible Vault for Credentials

Store sensitive credentials such as Windows admin passwords and service account credentials securely using Ansible Vault. Create an encrypted variables file:

ansible-vault create group_vars/windows_servers/vault.yml
# Enter the vault password when prompted, then add:
# vault_ansible_password: "AdminP@ssw0rd123"
# vault_domain_admin_password: "DomainAdmin@123"
# vault_service_account_password: "SvcAccount@456"

Reference vault variables in your inventory and playbooks:

# group_vars/windows_servers/vars.yml
ansible_password: "{{ vault_ansible_password }}"

# Run playbooks with vault password
ansible-playbook -i inventory.ini site.yml --ask-vault-pass
ansible-playbook -i inventory.ini site.yml --vault-password-file ~/.ansible_vault_pass

Ansible for Windows Server 2019 provides a powerful, agentless automation platform that enables consistent configuration management, application deployment, and patch management across large Windows server fleets using familiar YAML syntax and an extensive library of Windows-specific modules.