How to Install Ansible and Manage Windows Server 2012 R2 with Ansible
Ansible is an agentless configuration management and automation platform that manages Windows hosts via WinRM (Windows Remote Management) rather than SSH. This makes it an excellent choice for automating Windows Server 2012 R2 deployments, as no software needs to be installed on the managed Windows node itself — only WinRM must be properly configured. The Ansible control node (which runs the Ansible engine) is typically a Linux machine, though Windows Subsystem for Linux can also be used. This tutorial covers configuring WS2012 R2 as an Ansible-managed node, installing Ansible on a Linux control node, and writing and running playbooks to manage the Windows server.
Prerequisites
- Windows Server 2012 R2 target node with PowerShell 4.0
- A Linux control node (Ubuntu, CentOS, or Debian) with Python 3.8+ and pip
- Network connectivity between the control node and the Windows target on TCP port 5985 (WinRM HTTP) or 5986 (WinRM HTTPS)
- A Windows administrator account or domain account with local admin rights on the target
Step 1: Configure WinRM on Windows Server 2012 R2
Ansible communicates with Windows hosts exclusively over WinRM. On the Windows target, run the Ansible-provided WinRM configuration script as a local administrator. Download and execute it from a PowerShell session:
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1" -OutFile "C:TempConfigureWinRM.ps1"
Set-ExecutionPolicy Bypass -Scope Process -Force
.C:TempConfigureWinRM.ps1
This script performs several operations: enables the WinRM service, creates an HTTPS listener with a self-signed certificate, opens firewall ports 5985 and 5986, and sets the authentication method to negotiate (NTLM/Kerberos). For air-gapped environments, copy the script to the server manually and run it locally.
Verify WinRM is listening correctly:
winrm enumerate winrm/config/listener
netstat -ano | findstr "5985|5986"
Enable Basic authentication if you will use local Windows accounts (less secure but simpler for testing):
winrm set winrm/config/service/auth '@{Basic="true"}'
winrm set winrm/config/service '@{AllowUnencrypted="false"}'
Step 2: Install Ansible on the Linux Control Node
On your Linux control node, install Ansible and the required Python WinRM libraries:
sudo apt-get update
sudo apt-get install -y python3 python3-pip
pip3 install ansible pywinrm requests-kerberos requests-ntlm
For Red Hat/CentOS-based control nodes:
sudo yum install -y python3 python3-pip
pip3 install ansible pywinrm
Verify Ansible installed correctly:
ansible --version
Step 3: Create the Ansible Inventory File
Create a project directory and an inventory file that defines your Windows Server 2012 R2 hosts:
mkdir ~/ansible-windows && cd ~/ansible-windows
cat > inventory.ini << 'EOF'
[windows_servers]
ws2012r2-01.domain.local
[windows_servers:vars]
ansible_user=Administrator
ansible_password=YourAdminPassword
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_winrm_server_cert_validation=ignore
ansible_port=5986
ansible_winrm_scheme=https
EOF
For production use, store credentials in an Ansible Vault-encrypted file rather than in plain text in the inventory:
ansible-vault create group_vars/windows_servers/vault.yml
# Add these variables inside the vault:
# ansible_user: Administrator
# ansible_password: YourSecurePassword
Step 4: Test the WinRM Connection
Use the Ansible ping module for Windows (win_ping) to verify connectivity:
ansible windows_servers -i inventory.ini -m win_ping
A successful response looks like:
ws2012r2-01.domain.local | SUCCESS => {
"changed": false,
"ping": "pong"
}
If you receive a connection error, confirm that WinRM is running on the target, the firewall allows the traffic, and that the credentials are correct.
Step 5: Write a Basic Windows Playbook
Create a playbook that performs common administrative tasks on the Windows server:
cat > windows_baseline.yml << 'EOF'
---
- name: Windows Server 2012 R2 Baseline Configuration
hosts: windows_servers
gather_facts: yes
tasks:
- name: Ensure Windows Firewall is enabled for all profiles
win_firewall:
state: enabled
profiles:
- Domain
- Private
- Public
- name: Create standard directory structure
win_file:
path: "{{ item }}"
state: directory
loop:
- C:Apps
- C:Scripts
- C:Logs
- name: Set timezone to UTC
win_timezone:
timezone: UTC
- name: Ensure Windows Update service is running
win_service:
name: wuauserv
state: started
start_mode: auto
- name: Disable SMBv1
win_regedit:
path: HKLM:SYSTEMCurrentControlSetServicesLanmanServerParameters
name: SMB1
data: 0
type: dword
- name: Copy baseline configuration script
win_copy:
src: ./files/baseline.ps1
dest: C:Scriptsbaseline.ps1
- name: Run PowerShell command to collect system info
win_shell: |
$info = @{
ComputerName = $env:COMPUTERNAME
OSVersion = [System.Environment]::OSVersion.VersionString
PSVersion = $PSVersionTable.PSVersion.ToString()
AvailableRAM_GB = [Math]::Round((Get-WmiObject Win32_OperatingSystem).FreePhysicalMemory / 1MB, 2)
}
$info | ConvertTo-Json
register: sysinfo
- name: Show system info
debug:
msg: "{{ sysinfo.stdout }}"
EOF
Step 6: Install Windows Features with Ansible
The win_feature module manages Windows Server roles and features:
cat > install_iis.yml << 'EOF'
---
- name: Install and Configure IIS on WS2012 R2
hosts: windows_servers
tasks:
- name: Install IIS Web Server role
win_feature:
name:
- Web-Server
- Web-Common-Http
- Web-Static-Content
- Web-Default-Doc
- Web-Http-Errors
- Web-Asp-Net45
- Web-ISAPI-Ext
- Web-ISAPI-Filter
- Web-Mgmt-Console
state: present
include_management_tools: yes
register: iis_install
- name: Reboot if required after feature install
win_reboot:
reboot_timeout: 300
when: iis_install.reboot_required
- name: Ensure W3SVC service is started
win_service:
name: W3SVC
state: started
start_mode: auto
EOF
Run the playbook:
ansible-playbook -i inventory.ini install_iis.yml
Step 7: Use Ansible Roles for Reusable Configuration
For complex environments, structure your automation using Ansible roles. Create a basic role structure:
ansible-galaxy init roles/windows_baseline
# Creates:
# roles/windows_baseline/
# tasks/main.yml
# handlers/main.yml
# vars/main.yml
# defaults/main.yml
# templates/
# files/
Place task definitions in roles/windows_baseline/tasks/main.yml and reference the role from a site-level playbook. This approach enables you to manage dozens of Windows servers with consistent, versioned configuration.
Step 8: Schedule Recurring Ansible Runs
On the Linux control node, use cron to run playbooks on a schedule for drift remediation:
crontab -e
# Add: Run baseline enforcement every night at 2 AM
0 2 * * * cd /home/ansible/ansible-windows && ansible-playbook -i inventory.ini windows_baseline.yml >> /var/log/ansible-windows.log 2>&1
Summary
You have configured Windows Server 2012 R2 as an Ansible-managed node using WinRM, installed Ansible with WinRM support on a Linux control node, created an inventory file with secure credential storage, and written playbooks that install Windows features, configure the registry, manage services, and run PowerShell commands remotely. This Ansible foundation enables repeatable, auditable, idempotent configuration management across your entire WS2012 R2 server fleet without installing any agent software on the managed Windows machines.