How to Install Ansible and Manage Windows Servers with Ansible on Windows Server 2025

Ansible is an agentless automation platform that manages remote systems by pushing configuration over existing protocols. On Linux targets Ansible uses SSH; on Windows targets it uses WinRM (Windows Remote Management), the native Windows remoting protocol. This means Windows Server 2025 machines can be fully managed without installing any agent — only WinRM must be configured. This guide covers setting up an Ansible control node on Linux, preparing Windows Server 2025 as a managed host, writing inventories, testing connectivity, and running the most useful Windows-specific modules.

Prerequisites

  • A Linux host (Ubuntu 22.04 / 24.04, RHEL 9, or Debian 12) as the Ansible control node
  • Python 3.9 or later on the control node
  • Windows Server 2025 as the managed host (Standard or Datacenter edition)
  • A local administrator account on the Windows Server 2025 target
  • Network connectivity on TCP 5985 (WinRM HTTP) or 5986 (WinRM HTTPS) between control node and managed host

Step 1: Install Ansible on the Control Node (Linux)

# Ubuntu / Debian
sudo apt update
sudo apt install -y python3 python3-pip python3-venv

# Create a virtual environment (recommended)
python3 -m venv ~/ansible-env
source ~/ansible-env/bin/activate

# Install Ansible and Windows support libraries
pip install --upgrade pip
pip install ansible pywinrm requests-ntlm requests-credssp

# Verify installation
ansible --version
python -c "import winrm; print('pywinrm OK')"

Install the Windows collection from Ansible Galaxy, which provides the win_* modules:

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

Step 2: Configure WinRM on Windows Server 2025

On the Windows Server 2025 target, open an elevated PowerShell prompt and run the following commands to enable and configure WinRM. Microsoft provides a convenience script for Ansible that handles the full setup:

# Enable PowerShell remoting (creates WinRM listener on port 5985)
Enable-PSRemoting -Force

# Allow unencrypted traffic for initial testing (HTTP / NTLM)
# In production always use HTTPS (port 5986)
Set-Item -Path WSMan:localhostServiceAllowUnencrypted -Value $true

# Allow basic and NTLM authentication
Set-Item -Path WSMan:localhostServiceAuthBasic -Value $true
Set-Item -Path WSMan:localhostServiceAuthNTLM -Value $true

# Set the maximum memory per shell (increase for complex tasks)
Set-Item -Path WSMan:localhostShellMaxMemoryPerShellMB -Value 1024

# Configure WinRM service startup and start it
Set-Service -Name WinRM -StartupType Automatic
Start-Service WinRM

# Open firewall ports
New-NetFirewallRule -DisplayName "WinRM HTTP (5985)" `
    -Direction Inbound -Protocol TCP -LocalPort 5985 -Action Allow
New-NetFirewallRule -DisplayName "WinRM HTTPS (5986)" `
    -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow

# Test the WinRM listener
winrm enumerate winrm/config/Listener

For automated, repeatable configuration across many machines, use the ConfigureRemotingForAnsible.ps1 script maintained in the Ansible documentation repository. Download and run it on each managed Windows host:

$url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
$scriptPath = "$env:TEMPConfigureRemotingForAnsible.ps1"
Invoke-WebRequest -Uri $url -OutFile $scriptPath

# Run with HTTPS and CredSSP enabled
powershell -ExecutionPolicy Bypass -File $scriptPath -EnableCredSSP -ForceNewSSLCert -SkipNetworkProfileCheck

Step 3: Build the Ansible Inventory

On the control node create an inventory file that defines your Windows hosts and their connection parameters. Use INI or YAML format — YAML is clearer for complex variable sets:

# /etc/ansible/inventory/windows.yml  (YAML inventory)
all:
  children:
    windows:
      hosts:
        win-srv-01:
          ansible_host: 192.168.10.20
        win-srv-02:
          ansible_host: 192.168.10.21
      vars:
        ansible_user: Administrator
        ansible_password: "S3cur3P@ss2025!"
        ansible_connection: winrm
        ansible_winrm_transport: ntlm
        ansible_winrm_server_cert_validation: ignore
        ansible_winrm_port: 5985
        ansible_shell_type: powershell

Store credentials in an Ansible Vault file instead of plain text:

# Create an encrypted vault file
ansible-vault create /etc/ansible/inventory/windows_vault.yml

# Inside the vault file
vault_win_password: "S3cur3P@ss2025!"

# Reference the vault variable in inventory
# ansible_password: "{{ vault_win_password }}"

# Run Ansible commands with vault decryption
ansible windows -m win_ping --ask-vault-pass
# or use a vault password file
ansible windows -m win_ping --vault-password-file ~/.vault_pass.txt

Step 4: Test Connectivity with win_ping

# Test all hosts in the [windows] group
ansible windows -i /etc/ansible/inventory/windows.yml -m win_ping

# Expected successful output:
# win-srv-01 | SUCCESS => {
#     "changed": false,
#     "ping": "pong"
# }

# Test a single host
ansible win-srv-01 -i /etc/ansible/inventory/windows.yml -m win_ping -v

Step 5: Run Windows Modules — win_package, win_feature, win_service

Ansible’s Windows collection provides purpose-built modules for Windows administration. Run them ad-hoc or inside playbooks.

Install a Windows Feature

ansible windows -i inventory/windows.yml -m ansible.windows.win_feature -a "name=Web-Server state=present include_management_tools=yes"

Manage Windows Services

ansible windows -i inventory/windows.yml -m ansible.windows.win_service -a "name=W32Time state=started start_mode=auto"

Copy Files to Windows Hosts

ansible windows -i inventory/windows.yml -m ansible.windows.win_copy -a "src=/tmp/config.xml dest=C:\App\config.xml"

Step 6: Write a Windows Playbook

A playbook groups multiple tasks into a repeatable, idempotent automation unit:

# playbooks/configure_iis_server.yml
---
- name: Configure IIS on Windows Server 2025
  hosts: windows
  gather_facts: true

  tasks:
    - name: Install IIS and management tools
      ansible.windows.win_feature:
        name:
          - Web-Server
          - Web-Mgmt-Tools
          - Web-Asp-Net45
        state: present
        include_sub_features: true

    - name: Ensure IIS service is started and set to auto
      ansible.windows.win_service:
        name: W3SVC
        state: started
        start_mode: auto

    - name: Deploy application web.config
      ansible.windows.win_copy:
        src: files/web.config
        dest: C:inetpubwwwrootweb.config
        backup: true

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

    - name: Install Chocolatey package manager
      community.windows.win_chocolatey:
        name: chocolatey
        state: present

    - name: Install application prerequisites via Chocolatey
      community.windows.win_chocolatey:
        name:
          - dotnet-8.0-runtime
          - nssm
        state: present

    - name: Set environment variable for application
      ansible.windows.win_environment:
        name: APP_ENVIRONMENT
        value: Production
        state: present
        level: machine

    - name: Run post-deployment validation script
      ansible.windows.win_shell: |
        $response = Invoke-WebRequest -Uri http://localhost -UseBasicParsing
        if ($response.StatusCode -ne 200) {
          throw "IIS health check failed with status $($response.StatusCode)"
        }
        Write-Output "IIS health check passed"
      register: health_check_result

    - name: Display health check output
      debug:
        var: health_check_result.stdout_lines
# Run the playbook
ansible-playbook -i inventory/windows.yml playbooks/configure_iis_server.yml -v

# Dry-run (check mode)
ansible-playbook -i inventory/windows.yml playbooks/configure_iis_server.yml --check --diff

Step 7: Gather Windows Facts

Ansible’s setup module (called automatically at the start of plays) collects extensive facts about Windows hosts:

ansible win-srv-01 -i inventory/windows.yml -m ansible.windows.win_disk_facts
ansible win-srv-01 -i inventory/windows.yml -m setup -a "filter=ansible_os_family"

# Use facts in playbooks
- name: Show Windows version
  debug:
    msg: "{{ ansible_distribution }} {{ ansible_distribution_version }}"

Conclusion

Ansible transforms Windows Server 2025 administration from a series of manual Remote Desktop sessions into a repeatable, version-controlled, and auditable automation practice. By enabling WinRM with NTLM authentication, organizing managed hosts into inventory groups, storing secrets in Ansible Vault, and composing idempotent playbooks with the ansible.windows collection, teams can manage dozens or hundreds of Windows Server 2025 instances with confidence. As the environment grows, consider integrating Ansible with AWX or Red Hat Ansible Automation Platform for a web-based dashboard, role-based access control, and scheduled job execution across your entire Windows server fleet.