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:

  1. Sends a reboot command to the Windows host
  2. Waits for the host to become unreachable
  3. Polls until the host responds to WinRM
  4. Runs a test command to verify the system is fully operational
  5. Returns the elapsed time

Requirement: The connection user must have SeRemoteShutdownPrivilege.

Install the Collection

ansible-galaxy collection install ansible.windows

Parameters Reference

ParameterTypeDefaultDescription
reboot_timeoutint600Max seconds to wait for reboot to complete
msgstring"Reboot initiated by Ansible"Message shown to logged-in users
pre_reboot_delayint2Seconds to wait before rebooting
post_reboot_delayint0Seconds to wait after reboot before testing
connect_timeoutint5WinRM connection timeout per attempt
test_commandstring(detect logon screen)Command to verify system is ready
boot_time_commandstring(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

Featurewin_rebootreboot
PlatformWindowsLinux/Unix
ConnectionWinRMSSH
Test methodPowerShell/logon/bin/true or custom
Default timeout600s600s
User notificationYes (msg)Yes (msg)

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.