How to Install Ansible and Manage Windows Servers with Ansible on Windows Server 2022
Ansible is an agentless automation platform that uses SSH for Linux and WinRM for Windows to execute configuration management tasks, application deployments, and orchestrated workflows across infrastructure. Unlike agent-based tools, Windows servers do not require any Ansible software installed — only the WinRM service and the correct authentication configuration. This guide covers installing Ansible on a Linux control node, configuring Windows hosts, testing connectivity, and using the most common Ansible Windows modules.
Installing Ansible on the Linux Control Node
Ansible must be installed on a Linux (or macOS) control node. It cannot run its control plane natively on Windows, though WSL2 is a supported workaround for Windows development machines. For production use, a dedicated Linux server (Ubuntu 22.04 LTS or RHEL 9 are common choices) is recommended as the control node.
On Ubuntu 22.04, install Ansible using pip to ensure you get the latest version rather than the older package from the distribution repositories:
sudo apt update
sudo apt install -y python3 python3-pip python3-venv
# Create a virtual environment for Ansible
python3 -m venv /opt/ansible-venv
source /opt/ansible-venv/bin/activate
# Install Ansible and the WinRM library
pip install ansible pywinrm requests-kerberos requests-credssp
Verify the installation:
ansible --version
The pywinrm library is the Python package that Ansible uses to communicate with Windows hosts over WinRM. It must be installed in the same Python environment as Ansible. The requests-kerberos and requests-credssp packages are needed for Kerberos and CredSSP authentication modes respectively.
Configuring Windows Hosts for Ansible (WinRM Setup)
Windows Server 2022 has WinRM installed by default, but it is not configured for remote access. Microsoft provides a PowerShell script (ConfigureRemotingForAnsible.ps1) that automates the WinRM configuration. Download and run it on each Windows host you want to manage:
# Run this on the Windows Server 2022 host (elevated PowerShell)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
$file = "$env:tempConfigureRemotingForAnsible.ps1"
(New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
powershell.exe -ExecutionPolicy ByPass -File $file
This script performs several configuration steps: starts the WinRM service, creates HTTPS and HTTP listeners, configures the Windows Firewall to allow WinRM connections, and sets the WinRM service to start automatically. Verify WinRM is active:
winrm enumerate winrm/config/listener
You should see listeners for both HTTP (port 5985) and HTTPS (port 5986). For production environments, use HTTPS only and disable the HTTP listener after confirming HTTPS connectivity works.
Creating the Windows Inventory File
Ansible uses an inventory file to define the hosts and groups it manages. Create an inventory file on the control node:
# /etc/ansible/inventories/windows.ini
[windows]
ws2022-01 ansible_host=192.168.1.10
ws2022-02 ansible_host=192.168.1.11
ws2022-03 ansible_host=192.168.1.12
[windows:vars]
ansible_user=Administrator
ansible_password=YourAdminPassword
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_winrm_server_cert_validation=ignore
ansible_port=5986
For larger environments, use a YAML-format inventory and store credentials in Ansible Vault rather than plaintext. A YAML inventory for Windows hosts:
# inventory/windows.yml
all:
children:
windows:
hosts:
ws2022-01:
ansible_host: 192.168.1.10
ws2022-02:
ansible_host: 192.168.1.11
vars:
ansible_user: ansible_svc
ansible_password: "{{ vault_windows_password }}"
ansible_connection: winrm
ansible_winrm_transport: ntlm
ansible_winrm_server_cert_validation: ignore
ansible_port: 5986
Configuring ansible.cfg
The ansible.cfg file controls Ansible’s behavior for the current project. Create it in the same directory as your playbooks:
[defaults]
inventory = ./inventory/windows.yml
remote_user = ansible_svc
host_key_checking = False
timeout = 30
forks = 10
log_path = /var/log/ansible.log
[winrm]
operation_timeout_sec = 60
read_timeout_sec = 70
The forks setting controls how many hosts Ansible manages in parallel. A value of 10 means Ansible will execute tasks on up to 10 Windows hosts simultaneously. Increase this for larger environments, but be mindful of the network and target host load.
Testing Connectivity with win_ping
Before running any playbooks, verify basic connectivity to your Windows hosts using the win_ping module. This module sends a test message to the Windows host over WinRM and expects a response — it is the Windows equivalent of the Linux ping module:
ansible windows -i inventory/windows.yml -m win_ping
Successful output looks like:
ws2022-01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ws2022-02 | SUCCESS => {
"changed": false,
"ping": "pong"
}
If you get connection refused or authentication errors, check that WinRM is running, the firewall rule is in place, and the credentials are correct. Use the -vvv flag for verbose output that shows the exact WinRM negotiation:
ansible windows -i inventory/windows.yml -m win_ping -vvv
Ansible Playbook Basics for Windows
Playbooks are YAML files that define the automation tasks to perform. A basic Windows playbook might configure IIS, copy web files, and start the web service:
---
- name: Configure IIS Web Server
hosts: windows
gather_facts: true
tasks:
- name: Install IIS Web Server role
ansible.windows.win_feature:
name: Web-Server
state: present
include_management_tools: true
- name: Ensure IIS service is started
ansible.windows.win_service:
name: W3SVC
state: started
start_mode: auto
- name: Copy application files
ansible.windows.win_copy:
src: ./webapp/
dest: C:inetpubwwwrootmyapp
- name: Create firewall rule for HTTP
community.windows.win_firewall_rule:
name: "Allow HTTP 80"
localport: 80
action: allow
direction: in
protocol: tcp
state: present
enabled: true
Run the playbook with:
ansible-playbook -i inventory/windows.yml playbooks/configure_iis.yml
Common Windows Ansible Modules
The ansible.windows collection provides the core Windows modules. Install or update it with:
ansible-galaxy collection install ansible.windows community.windows
The win_command module runs a Windows command without shell processing. Use it for executables that do not require shell features:
- name: Run a program
ansible.windows.win_command: C:Toolsmyapp.exe --install --silent
The win_shell module runs commands through PowerShell or cmd, enabling shell features like pipes, redirects, and variable expansion:
- name: Get disk usage
ansible.windows.win_shell: Get-PSDrive C | Select-Object Used, Free
register: disk_info
- name: Show disk info
debug:
var: disk_info.stdout
The win_copy module copies files and directories from the control node to Windows hosts:
- name: Copy configuration file
ansible.windows.win_copy:
src: configs/app.config
dest: C:Appapp.config
backup: true
The win_file module manages files and directories:
- name: Create directory
ansible.windows.win_file:
path: C:LogsMyApp
state: directory
- name: Delete old log files
ansible.windows.win_file:
path: C:LogsMyAppold
state: absent
The win_service module manages Windows services — starting, stopping, enabling, and disabling them:
- name: Ensure SQL Server is running
ansible.windows.win_service:
name: MSSQLSERVER
state: started
start_mode: auto
- name: Disable Windows Search
ansible.windows.win_service:
name: WSearch
state: stopped
start_mode: disabled
The win_feature module installs or removes Windows Server roles and features:
- name: Install .NET Framework 4.8
ansible.windows.win_feature:
name: NET-Framework-45-Features
state: present
- name: Install Hyper-V management tools
ansible.windows.win_feature:
name:
- Hyper-V-Tools
- Hyper-V-PowerShell
state: present
The win_package module installs or uninstalls Windows software packages (MSI, EXE installers):
- name: Install 7-Zip
ansible.windows.win_package:
path: C:Installers7z2301-x64.msi
state: present
arguments: /quiet /norestart
- name: Install from URL
ansible.windows.win_package:
path: https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v8.6.5/npp.8.6.5.Installer.x64.exe
state: present
arguments: /S
Running Ansible Over HTTPS WinRM
For production environments, use HTTPS WinRM (port 5986) to encrypt traffic between the Ansible control node and Windows hosts. Verify the HTTPS listener is active on the Windows host:
winrm enumerate winrm/config/listener
In your inventory, set ansible_port to 5986 and ansible_winrm_scheme to https. If using self-signed certificates (as created by ConfigureRemotingForAnsible.ps1), set ansible_winrm_server_cert_validation to ignore for initial testing, then replace with a proper certificate from your internal CA for production:
ansible_port: 5986
ansible_winrm_scheme: https
ansible_winrm_server_cert_validation: ignore # Change to 'validate' with a trusted cert
ansible_winrm_transport: ntlm
To use a trusted certificate, export your internal CA certificate as a PEM file and reference it in your inventory:
ansible_winrm_ca_trust_path: /etc/ansible/certs/internal-ca.pem
ansible_winrm_server_cert_validation: validate
With HTTPS and certificate validation enabled, all Ansible communications to your Windows Server 2022 fleet are encrypted and authenticated, meeting the security requirements of most enterprise environments.