--- - name: Check for pending reboot before patching ansible.windows.win_reboot: reboot_timeout: 300 pre_reboot_delay: 10 post_reboot_delay: 30 msg: "Rebooting to clear pending reboot state before patching" when: pre_patch_reboot | bool - name: Get installed updates before patching ansible.windows.win_shell: | Get-HotFix | Select-Object -Property HotFixID, Description, InstalledOn | ConvertTo-Json register: hotfixes_before changed_when: false - name: Store pre-patch hotfix list ansible.builtin.set_fact: windows_hotfixes_before: "{{ hotfixes_before.stdout | from_json }}" - name: Search for available updates ansible.windows.win_updates: category_names: "{{ windows_update_categories }}" state: searched register: updates_available - name: Log available updates ansible.builtin.debug: msg: "{{ updates_available.found_update_count }} updates available on {{ inventory_hostname }}" - name: Install Windows updates ansible.windows.win_updates: category_names: "{{ windows_update_categories }}" state: installed reboot: false register: windows_update_result when: updates_available.found_update_count > 0 - name: Get installed updates after patching ansible.windows.win_shell: | Get-HotFix | Select-Object -Property HotFixID, Description, InstalledOn | ConvertTo-Json register: hotfixes_after changed_when: false - name: Store post-patch hotfix list ansible.builtin.set_fact: windows_hotfixes_after: "{{ hotfixes_after.stdout | from_json }}" - name: Build list of newly installed KBs ansible.builtin.set_fact: packages_updated: >- {%- set before_ids = windows_hotfixes_before | map(attribute='HotFixID') | list -%} {%- set updated = [] -%} {%- for fix in windows_hotfixes_after -%} {%- if fix.HotFixID not in before_ids -%} {%- set _ = updated.append({ 'name': fix.HotFixID, 'version_before': 'not installed', 'version_after': fix.InstalledOn, 'type': fix.Description }) -%} {%- endif -%} {%- endfor -%} {{ updated }} - name: Log newly installed KBs ansible.builtin.debug: msg: "Installed: {{ item.name }} — {{ item.type }}" loop: "{{ packages_updated }}" - name: Check if reboot is required ansible.windows.win_shell: | $rebootPending = $false if (Get-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" -ErrorAction SilentlyContinue) { $rebootPending = $true } if (Get-Item "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations" -ErrorAction SilentlyContinue) { $rebootPending = $true } Write-Output $rebootPending register: windows_reboot_check changed_when: false - name: Set reboot required fact ansible.builtin.set_fact: host_reboot_required: "{{ windows_reboot_check.stdout | trim | bool }}" - name: Reboot if required and auto_reboot is enabled ansible.windows.win_reboot: reboot_timeout: 300 pre_reboot_delay: 10 post_reboot_delay: 60 msg: "Rebooting after patch run — initiated by Ansible" when: - host_reboot_required | bool - auto_reboot | bool - name: Patching complete ansible.builtin.debug: msg: "Windows patching complete on {{ inventory_hostname }} — {{ packages_updated | length }} KBs installed"