Introduction
Rebooting Windows servers is required after system updates, driver installations, domain joins, and configuration changes. The ansible.windows.win_reboot module handles the entire reboot cycle — initiating the restart, waiting for the host to go down, and verifying it's back online and responsive.
For Linux/Unix targets, use ansible.builtin.reboot instead.
The ansible.windows.win_reboot Module
Part of the ansible.windows collection. The module:
- Sends a reboot command to the Windows host
- Waits for the host to become unreachable
- Polls until the host responds to WinRM
- Runs a test command to verify the system is fully operational
- Returns the elapsed time
Requirement: The connection user must have SeRemoteShutdownPrivilege.
Install the Collection
ansible-galaxy collection install ansible.windows
Parameters Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
reboot_timeout | int | 600 | Max seconds to wait for reboot to complete |
msg | string | "Reboot initiated by Ansible" | Message shown to logged-in users |
pre_reboot_delay | int | 2 | Seconds to wait before rebooting |
post_reboot_delay | int | 0 | Seconds to wait after reboot before testing |
connect_timeout | int | 5 | WinRM connection timeout per attempt |
test_command | string | (detect logon screen) | Command to verify system is ready |
boot_time_command | string | (Get-CimInstance...) | Command to detect boot time |
Basic Examples
Simple Reboot
---
- name: Reboot Windows server
hosts: windows
tasks:
- name: Reboot the host
ansible.windows.win_reboot:
Reboot with Custom Message and Delays
---
- name: Controlled reboot
hosts: windows
tasks:
- name: Reboot with warning
ansible.windows.win_reboot:
msg: "Server rebooting for maintenance - Ansible automated"
pre_reboot_delay: 30 # Give users 30s warning
post_reboot_delay: 60 # Wait 60s after reboot for services to start
reboot_timeout: 900 # Allow up to 15 minutes
Reboot with Custom Test Command
---
- name: Wait for specific service after reboot
hosts: windows
tasks:
- name: Reboot and wait for SQL Server
ansible.windows.win_reboot:
msg: "Rebooting for SQL Server update"
test_command: >-
powershell.exe -Command
"if ((Get-Service -Name MSSQLSERVER).Status -ne 'Running') { exit 1 }"
reboot_timeout: 900
Advanced Patterns
Conditional Reboot After Windows Update
---
- name: Windows patching with conditional reboot
hosts: windows
tasks:
- name: Install Windows updates
ansible.windows.win_updates:
category_names:
- SecurityUpdates
- CriticalUpdates
state: installed
register: update_result
- name: Reboot if required by updates
ansible.windows.win_reboot:
msg: "Rebooting after Windows updates"
pre_reboot_delay: 10
post_reboot_delay: 30
when: update_result.reboot_required
- name: Verify updates applied
ansible.windows.win_updates:
category_names:
- SecurityUpdates
- CriticalUpdates
state: searched
register: pending_updates
- name: Report update status
ansible.builtin.debug:
msg: "{{ pending_updates.found_update_count }} updates still pending"
Rolling Reboot (Load-Balanced Servers)
---
- name: Rolling reboot of web farm
hosts: iis_servers
serial: 1 # One server at a time
tasks:
- name: Remove from load balancer
ansible.windows.win_uri:
url: "https://lb.example.com/api/disable/{{ inventory_hostname }}"
method: POST
headers:
Authorization: "Bearer {{ lb_token }}"
delegate_to: localhost
- name: Wait for connections to drain
ansible.builtin.pause:
seconds: 30
- name: Reboot server
ansible.windows.win_reboot:
msg: "Scheduled maintenance reboot"
post_reboot_delay: 30
reboot_timeout: 600
- name: Verify IIS is running
ansible.windows.win_service:
name: W3SVC
register: iis_status
until: iis_status.state == "running"
retries: 10
delay: 10
- name: Add back to load balancer
ansible.windows.win_uri:
url: "https://lb.example.com/api/enable/{{ inventory_hostname }}"
method: POST
headers:
Authorization: "Bearer {{ lb_token }}"
delegate_to: localhost
Reboot After Domain Join
---
- name: Join domain and reboot
hosts: new_windows_servers
tasks:
- name: Join Active Directory domain
microsoft.ad.membership:
dns_domain_name: corp.example.com
domain_admin_user: "{{ domain_admin }}"
domain_admin_password: "{{ domain_password }}"
state: domain
register: domain_join
- name: Reboot after domain join
ansible.windows.win_reboot:
msg: "Rebooting after domain join"
post_reboot_delay: 60
reboot_timeout: 900
when: domain_join.reboot_required
Handling Reboot Timeouts
---
- name: Reboot with error handling
hosts: windows
tasks:
- name: Attempt reboot
ansible.windows.win_reboot:
reboot_timeout: 300
register: reboot_result
ignore_errors: true
- name: Handle failed reboot
when: reboot_result is failed
block:
- name: Log failure
ansible.builtin.debug:
msg: "WARNING: {{ inventory_hostname }} failed to reboot within timeout"
- name: Send alert
ansible.builtin.uri:
url: "https://alerts.example.com/webhook"
method: POST
body_format: json
body:
text: "Server {{ inventory_hostname }} failed to reboot"
delegate_to: localhost
Complete Playbook: Monthly Windows Maintenance
---
- name: Monthly Windows server maintenance
hosts: windows_servers
serial: "25%"
vars:
maintenance_window: true
max_reboot_time: 900
tasks:
- name: Verify maintenance window
ansible.builtin.assert:
that: maintenance_window | bool
fail_msg: "Maintenance window not active — aborting"
- name: Clear temp files
ansible.windows.win_shell: |
Remove-Item -Path "$env:TEMP\*" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "C:\Windows\Temp\*" -Recurse -Force -ErrorAction SilentlyContinue
changed_when: true
- name: Install security updates
ansible.windows.win_updates:
category_names:
- SecurityUpdates
- CriticalUpdates
- UpdateRollups
state: installed
reboot: false # We'll handle reboot ourselves
register: updates
- name: Display installed updates
ansible.builtin.debug:
msg: "Installed {{ updates.installed_update_count }} updates on {{ inventory_hostname }}"
- name: Reboot if required
ansible.windows.win_reboot:
msg: "Monthly maintenance reboot - {{ updates.installed_update_count }} updates installed"
pre_reboot_delay: 10
post_reboot_delay: 60
reboot_timeout: "{{ max_reboot_time }}"
when: updates.reboot_required
- name: Verify critical services
ansible.windows.win_service:
name: "{{ item }}"
register: service_check
failed_when: service_check.state != "running"
loop:
- W3SVC
- WinRM
- EventLog
- name: Report success
ansible.builtin.debug:
msg: "{{ inventory_hostname }} maintenance complete. Updates: {{ updates.installed_update_count }}, Rebooted: {{ updates.reboot_required }}"
Troubleshooting
Timeout Exceeded
fatal: [server]: FAILED! => {"changed": false, "elapsed": 600, "msg": "Timed out waiting for last boot time check"}
Fix: Increase reboot_timeout (especially for servers with many services):
ansible.windows.win_reboot:
reboot_timeout: 1200 # 20 minutes
Permission Denied
fatal: [server]: FAILED! => {"msg": "Access is denied"}
Fix: Ensure the WinRM user has SeRemoteShutdownPrivilege. Run on the target:
secedit /export /areas USER_RIGHTS /cfg c:\temp\rights.inf
# Add user to SeRemoteShutdownPrivilege
WinRM Connection Refused After Reboot
Cause: WinRM service starts late, or firewall rules reset.
Fix: Increase post_reboot_delay:
ansible.windows.win_reboot:
post_reboot_delay: 120 # Wait 2 minutes for all services
connect_timeout: 10 # Longer per-attempt timeout
win_reboot vs reboot Module
| Feature | win_reboot | reboot |
|---|---|---|
| Platform | Windows | Linux/Unix |
| Connection | WinRM | SSH |
| Test method | PowerShell/logon | /bin/true or custom |
| Default timeout | 600s | 600s |
| User notification | Yes (msg) | Yes (msg) |
Related Articles
- Ansible Windows Automation — Windows module basics
- Ansible reboot Module — Linux reboots
- Ansible win_updates — Windows patching
- Ansible Serial Rolling Updates — Rolling deployments
Conclusion
The ansible.windows.win_reboot module safely handles the full reboot cycle — notification, shutdown, wait, and verification. Always set appropriate timeouts for your environment, use post_reboot_delay for servers with slow-starting services, and combine with serial for rolling reboots in load-balanced environments. Check reboot_required from win_updates to avoid unnecessary reboots.