Update role dependencies
This commit is contained in:
@@ -14,6 +14,10 @@ Role Variables
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
A list of roles that this role utilizes:
|
||||
|
||||
- oatakan.windows_hotfix
|
||||
|
||||
Example Playbook
|
||||
----------------
|
||||
|
||||
@@ -36,7 +40,7 @@ Including an example of how to use your role (for instance, with variables passe
|
||||
|
||||
For disconnected environments, you can overwrite this variable to point to a local copy of a script to enable winrm:
|
||||
|
||||
**winrm_enable_script_url:** https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1
|
||||
**winrm_enable_script_url:** https://raw.githubusercontent.com/ansible/ansible-documentation/devel/examples/scripts/ConfigureRemotingForAnsible.ps1
|
||||
|
||||
you can also localize virtio-win and update the virtio_iso_url variable to point to your local url:
|
||||
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
---
|
||||
|
||||
install_updates_retry_limit: 300
|
||||
update_retry_count: 0
|
||||
update_retry_limit: 10
|
||||
win_update_category_names:
|
||||
- CriticalUpdates
|
||||
- DefinitionUpdates
|
||||
- SecurityUpdates
|
||||
- UpdateRollups
|
||||
- Updates
|
||||
|
||||
hotfix_download_location: "{{ ansible_env.TEMP }}"
|
||||
win_update_category_names: '*'
|
||||
#win_update_category_names:
|
||||
# - CriticalUpdates
|
||||
# - DefinitionUpdates
|
||||
# - FeaturePacks
|
||||
# - SecurityUpdates
|
||||
# - UpdateRollups
|
||||
# - Updates
|
||||
|
||||
hotfixes_group_1:
|
||||
win_update_reject_list: []
|
||||
win_update_accept_list: []
|
||||
win_update_server_selection: default
|
||||
win_update_disable_firewall: yes
|
||||
failed_kb: []
|
||||
|
||||
windows_update_disable_firewall: true
|
||||
|
||||
temp_directory: "{{ ansible_env.TEMP }}"
|
||||
|
||||
windows_hotfix_role: oatakan.windows_hotfix
|
||||
|
||||
hotfixes:
|
||||
- kb: KB3020369
|
||||
file: Windows6.1-KB3020369-x64.msu
|
||||
url: https://download.microsoft.com/download/F/D/3/FD3728D5-0D2F-44A6-B7DA-1215CC0C9B75/Windows6.1-KB3020369-x64.msu
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
---
|
||||
|
||||
- name: get Windows ADK uninstall command
|
||||
win_reg_stat:
|
||||
path: HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{d794748d-72e9-45d7-9ab7-83d6c4c80f7f}
|
||||
name: QuietUninstallString
|
||||
register: windows_adk_uninstall_string
|
||||
|
||||
- name: uninstall Windows ADK
|
||||
win_shell: "{{ windows_adk_uninstall_string.value }}"
|
||||
args:
|
||||
executable: cmd
|
||||
when: windows_adk_uninstall_string.value is defined
|
||||
|
||||
- name: ensure Windows ADK with DISM is removed
|
||||
win_chocolatey:
|
||||
name: windows-adk-deploy
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
install_date: Fri Oct 15 18:59:19 2021
|
||||
install_date: Thu 08 Feb 2024 08:54:03 PM
|
||||
version: master
|
||||
|
||||
@@ -1,18 +1,33 @@
|
||||
---
|
||||
|
||||
- debug:
|
||||
msg: "win update server: {{ win_update_server }}"
|
||||
when: win_update_server is defined
|
||||
|
||||
- name: disable firewall for Domain, Public and Private profiles
|
||||
win_shell: Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
|
||||
when: "'Windows Server 2012' in ansible_distribution"
|
||||
when:
|
||||
- "'Windows Server 2012' in ansible_distribution or 'Windows 8' in ansible_distribution"
|
||||
- windows_update_disable_firewall | bool
|
||||
|
||||
- name: disable firewall for Domain, Public and Private profiles
|
||||
win_shell: netsh advfirewall set allprofiles state off
|
||||
when: "'Windows Server 2008' in ansible_distribution or 'Windows 7' in ansible_distribution"
|
||||
when:
|
||||
- "'Windows Server 2008' in ansible_distribution or 'Windows 7' in ansible_distribution"
|
||||
- windows_update_disable_firewall | bool
|
||||
|
||||
- name: get used space before update
|
||||
win_shell: Get-PSDrive C | Select-Object Used | ConvertTo-Json
|
||||
register: used_space_before_update
|
||||
ignore_errors: yes
|
||||
|
||||
- name: reset some facts
|
||||
set_fact:
|
||||
update_retry_count: 0
|
||||
missing_hotfixes: []
|
||||
failed_kb: []
|
||||
_reject_list: []
|
||||
|
||||
- include_tasks: updates-all.yml
|
||||
when:
|
||||
- "'Windows Server 2008' not in ansible_distribution"
|
||||
@@ -42,8 +57,12 @@
|
||||
|
||||
- name: enabled firewall for Domain, Public and Private profiles
|
||||
win_shell: Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
|
||||
when: "'Windows Server 2012' in ansible_distribution"
|
||||
when:
|
||||
- "'Windows Server 2012' in ansible_distribution or 'Windows 8' in ansible_distribution"
|
||||
- windows_update_disable_firewall | bool
|
||||
|
||||
- name: enable firewall for Domain, Public and Private profiles
|
||||
win_shell: netsh advfirewall set allprofiles state on
|
||||
when: "'Windows Server 2008' in ansible_distribution or 'Windows 7' in ansible_distribution"
|
||||
win_shell: netsh advfirewall set allprofiles state on
|
||||
when:
|
||||
- "'Windows Server 2008' in ansible_distribution or 'Windows 7' in ansible_distribution"
|
||||
- windows_update_disable_firewall | bool
|
||||
@@ -1,19 +1,32 @@
|
||||
---
|
||||
- block:
|
||||
- name: check for available updates
|
||||
win_updates:
|
||||
category_names: "{{ win_update_category_names }}"
|
||||
reject_list: "{{ win_update_reject_list | default(omit) }}"
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
state: searched
|
||||
register: available_updates
|
||||
rescue:
|
||||
- name: ensure we have connection
|
||||
wait_for_connection:
|
||||
|
||||
- name: check for available updates
|
||||
win_updates:
|
||||
category_names: "{{ win_update_category_names }}"
|
||||
blacklist: "{{ win_update_blacklist | default(omit) }}"
|
||||
state: searched
|
||||
register: available_updates
|
||||
- name: check for available updates (retry)
|
||||
win_updates:
|
||||
category_names: "{{ win_update_category_names }}"
|
||||
reject_list: "{{ win_update_reject_list | default(omit) }}"
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
state: searched
|
||||
register: available_updates
|
||||
|
||||
- debug:
|
||||
msg: |
|
||||
msg: "{{ _msg.split('\n')[:-1] }}"
|
||||
vars:
|
||||
_msg: |
|
||||
{{ inventory_hostname }} has {{ available_updates.found_update_count }} updates available.
|
||||
{% for update in updates %}
|
||||
- {{ update.title }}
|
||||
{% endfor %}
|
||||
vars:
|
||||
updates: "{{ (available_updates.updates.values() | list) if (available_updates.updates is mapping) else (available_updates.updates) }}"
|
||||
when: available_updates.updates is defined
|
||||
|
||||
@@ -22,8 +35,20 @@
|
||||
- available_updates.updates is defined
|
||||
- available_updates.found_update_count > 0
|
||||
|
||||
# see https://learn.microsoft.com/en-us/sharepoint/troubleshoot/administration/800703fa-illegal-operation-error
|
||||
# error code 0x800703FA happens with some updates when user is not logged in
|
||||
# remove the registry key if added during the update
|
||||
- include_tasks: force_user_registry.yml
|
||||
vars:
|
||||
task_state: absent
|
||||
when:
|
||||
- disable_force_unload_registry is defined
|
||||
- disable_force_unload_registry is not skipped
|
||||
- disable_force_unload_registry is changed
|
||||
|
||||
- name: check for missing updates
|
||||
win_updates:
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
state: searched
|
||||
register: available_updates
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
block:
|
||||
- name: check for available updates
|
||||
win_updates:
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
category_names:
|
||||
- CriticalUpdates
|
||||
- DefinitionUpdates
|
||||
@@ -14,16 +15,23 @@
|
||||
register: available_updates
|
||||
|
||||
- debug:
|
||||
msg: |
|
||||
msg: "{{ _msg.split('\n')[:-1] }}"
|
||||
vars:
|
||||
_msg: |
|
||||
{{ inventory_hostname }} has {{ available_updates.found_update_count }} updates available.
|
||||
{% for update in updates %}
|
||||
- {{ update.title }}
|
||||
{% endfor %}
|
||||
vars:
|
||||
updates: "{{ (available_updates.updates.values() | list) if (available_updates.updates is mapping) else (available_updates.updates) }}"
|
||||
when: available_updates.updates is defined
|
||||
|
||||
- block:
|
||||
- name: ensure there is connection
|
||||
wait_for_connection:
|
||||
delay: 60
|
||||
sleep: 10
|
||||
timeout: 600
|
||||
|
||||
- name: install windows updates using powershell script
|
||||
script: win-updates.ps1
|
||||
become: yes
|
||||
@@ -56,6 +64,7 @@
|
||||
when: update_reboot_required_key.exists
|
||||
|
||||
- name: check for missing updates
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
win_updates:
|
||||
category_names:
|
||||
- CriticalUpdates
|
||||
@@ -67,12 +76,13 @@
|
||||
register: missing_updates
|
||||
|
||||
- debug:
|
||||
msg: |
|
||||
msg: "{{ _msg.split('\n')[:-1] }}"
|
||||
vars:
|
||||
_msg: |
|
||||
{{ inventory_hostname }} has {{ missing_updates.found_update_count }} updates still missing.
|
||||
{% for update in updates %}
|
||||
- {{ update.title }}
|
||||
{% endfor %}
|
||||
vars:
|
||||
updates: "{{ (missing_updates.updates.values() | list) if (missing_updates.updates is mapping) else (missing_updates.updates) }}"
|
||||
when: missing_updates.updates is defined
|
||||
|
||||
|
||||
@@ -1,72 +1,40 @@
|
||||
---
|
||||
|
||||
- name: ensure Windows ADK with DISM is installed
|
||||
win_chocolatey:
|
||||
name: windows-adk-deploy
|
||||
state: present
|
||||
version: 10.0.17134.0
|
||||
register: install_windows_adk_deploy
|
||||
notify: ensure Windows ADK with DISM is removed
|
||||
- include_tasks: install_dism.yml
|
||||
|
||||
- name: ensure PATH contains Windows ADK
|
||||
win_path:
|
||||
scope: machine
|
||||
state: present
|
||||
elements: "C:\\Program Files (x86)\\Windows Kits\\10\\Assessment and Deployment Kit\\Deployment Tools\\amd64\\DISM"
|
||||
- name: check installed kbs
|
||||
win_shell: wmic qfe | ConvertTo-Json
|
||||
register: installed_kbs
|
||||
|
||||
- name: download hotfix group 1
|
||||
win_get_url:
|
||||
url: '{{ item.url }}'
|
||||
dest: '{{ hotfix_download_location }}\{{ item.file }}'
|
||||
loop: "{{ hotfixes_group_1 }}"
|
||||
- name: missing hotfixes
|
||||
set_fact:
|
||||
missing_hotfixes: "{{ hotfixes | json_query(query) }}"
|
||||
vars:
|
||||
set_installed_kbs: "{{ (installed_kbs.stdout | from_json) | reject('match', '^$') | reject('match', '^Caption *') | map('regex_replace', '^.* (KB[0-9]+) .*', '\\1') | list }}"
|
||||
query: "[?!contains(`{{ set_installed_kbs }}`, kb)]"
|
||||
|
||||
- block:
|
||||
- name: install hotfix group 1 (PS >= 4)
|
||||
win_hotfix:
|
||||
source: '{{ hotfix_download_location }}\{{ item.file }}'
|
||||
state: present
|
||||
register: hotfix_install_group_1
|
||||
loop: "{{ hotfixes_group_1 }}"
|
||||
when: ansible_powershell_version is version('4', '>=')
|
||||
rescue:
|
||||
- name: install hotfix using shell
|
||||
win_shell: '{{ hotfix_download_location }}\{{ item.file }} /quiet /norestart'
|
||||
register: hotfix_install_group_1
|
||||
loop: "{{ hotfixes_group_1 }}"
|
||||
|
||||
- name: install hotfix (PS == 3)
|
||||
win_shell: '{{ hotfix_download_location }}\{{ item.file }} /quiet /norestart'
|
||||
register: hotfix_install_group_1
|
||||
loop: "{{ hotfixes_group_1 }}"
|
||||
when: ansible_powershell_version is version('3', '==')
|
||||
|
||||
- name: debug hotfix installation result
|
||||
debug:
|
||||
var: hotfix_install_group_1
|
||||
|
||||
- name: ensure hotfix file is removed (group 1)
|
||||
win_file:
|
||||
path: '{{ hotfix_download_location }}\{{ item.file }}'
|
||||
state: absent
|
||||
loop: "{{ hotfixes_group_1 }}"
|
||||
|
||||
- name: reboot from starting update
|
||||
win_reboot:
|
||||
- include_role:
|
||||
name: "{{ windows_hotfix_role }}"
|
||||
loop: "{{ missing_hotfixes }}"
|
||||
loop_control:
|
||||
loop_var: hotfix
|
||||
|
||||
- name: check for available updates
|
||||
win_updates:
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
category_names: "{{ win_update_category_names }}"
|
||||
blacklist: "{{ win_update_blacklist | default(omit) }}"
|
||||
reject_list: "{{ win_update_reject_list | default(omit) }}"
|
||||
state: searched
|
||||
register: available_updates
|
||||
|
||||
- debug:
|
||||
msg: |
|
||||
msg: "{{ _msg.split('\n')[:-1] }}"
|
||||
vars:
|
||||
_msg: |
|
||||
{{ inventory_hostname }} has {{ available_updates.found_update_count }} updates available.
|
||||
{% for update in updates %}
|
||||
- {{ update.title }}
|
||||
{% endfor %}
|
||||
vars:
|
||||
updates: "{{ (available_updates.updates.values() | list) if (available_updates.updates is mapping) else (available_updates.updates) }}"
|
||||
when: available_updates.updates is defined
|
||||
|
||||
@@ -77,6 +45,7 @@
|
||||
|
||||
- name: check for missing updates.
|
||||
win_updates:
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
state: searched
|
||||
register: available_updates
|
||||
|
||||
|
||||
@@ -3,15 +3,54 @@
|
||||
- name: update over multiple reboots
|
||||
block:
|
||||
- block:
|
||||
- name: set reject list
|
||||
set_fact:
|
||||
_reject_list: "{{ (win_update_reject_list | default([])) + (failed_kb | default([])) }}"
|
||||
when: (win_update_reject_list | length) or (failed_kb | length)
|
||||
|
||||
- name: install all windows updates
|
||||
win_updates:
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
category_names: "{{ win_update_category_names }}"
|
||||
blacklist: "{{ (win_update_blacklist | default([])) + (failed_kb | default([])) }}"
|
||||
whitelist: "{{ win_update_whitelist | default(omit) }}"
|
||||
reboot: yes
|
||||
reject_list: "{{ _reject_list | default(omit) }}"
|
||||
accept_list: "{{ win_update_accept_list | default(omit) }}"
|
||||
reboot: false
|
||||
async: 7200
|
||||
poll: 0
|
||||
register: installed_updates_async
|
||||
|
||||
- name: wait for updates to finish
|
||||
async_status:
|
||||
jid: "{{ installed_updates_async.ansible_job_id }}"
|
||||
register: installed_updates
|
||||
until: installed_updates.finished
|
||||
retries: "{{ install_updates_retry_limit }}"
|
||||
delay: 30
|
||||
|
||||
- name: reboot the system if required
|
||||
win_reboot:
|
||||
reboot_timeout: 7200
|
||||
when: installed_updates.reboot_required
|
||||
|
||||
rescue:
|
||||
- name: ensure there is connection
|
||||
wait_for_connection:
|
||||
delay: 60
|
||||
sleep: 10
|
||||
timeout: 600
|
||||
|
||||
# see https://learn.microsoft.com/en-us/sharepoint/troubleshoot/administration/800703fa-illegal-operation-error
|
||||
# error code 0x800703FA happens with some updates when user is not logged in
|
||||
# add the registry key to disable forcefully unloading users registry at user logoff
|
||||
- include_tasks: force_user_registry.yml
|
||||
vars:
|
||||
task_state: present
|
||||
when:
|
||||
- installed_updates is defined
|
||||
- installed_updates is failed
|
||||
- installed_updates.msg is defined
|
||||
- ('0x800703FA' in installed_updates.msg)
|
||||
|
||||
- name: reboot the system to recover from a failed update
|
||||
win_reboot:
|
||||
reboot_timeout: 7200
|
||||
@@ -36,32 +75,50 @@
|
||||
delay: 60
|
||||
sleep: 10
|
||||
timeout: 600
|
||||
- block:
|
||||
- name: work on any skipped KB
|
||||
win_updates:
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
category_names: "{{ win_update_category_names }}"
|
||||
reject_list: "{{ win_update_reject_list | default(omit) }}"
|
||||
accept_list: "{{ failed_kb | default(omit) }}"
|
||||
reboot: false
|
||||
async: 7200
|
||||
poll: 0
|
||||
register: installed_updates_retry_skipped_async
|
||||
|
||||
- name: work on any skipped KB
|
||||
win_updates:
|
||||
category_names: "{{ win_update_category_names }}"
|
||||
blacklist: "{{ win_update_blacklist | default(omit) }}"
|
||||
whitelist: "{{ failed_kb | default([]) }}"
|
||||
reboot: yes
|
||||
register: installed_updates_retry_skipped
|
||||
- name: wait for updates to finish
|
||||
async_status:
|
||||
jid: "{{ installed_updates_retry_skipped_async.ansible_job_id }}"
|
||||
register: installed_updates_retry_skipped
|
||||
until: installed_updates_retry_skipped.finished
|
||||
retries: "{{ install_updates_retry_limit }}"
|
||||
delay: 30
|
||||
|
||||
- name: reboot the system if required
|
||||
win_reboot:
|
||||
reboot_timeout: 7200
|
||||
when: installed_updates_retry_skipped.reboot_required
|
||||
when:
|
||||
- failed_kb is defined
|
||||
- failed_kb | length > 0
|
||||
|
||||
- name: check for missing updates
|
||||
win_updates:
|
||||
server_selection: "{{ win_update_server_selection }}"
|
||||
category_names: "{{ win_update_category_names }}"
|
||||
blacklist: "{{ win_update_blacklist | default(omit) }}"
|
||||
reject_list: "{{ win_update_reject_list | default(omit) }}"
|
||||
state: searched
|
||||
register: missing_updates
|
||||
|
||||
- debug:
|
||||
msg: |
|
||||
msg: "{{ _msg.split('\n')[:-1] }}"
|
||||
vars:
|
||||
_msg: |
|
||||
{{ inventory_hostname }} has {{ missing_updates.found_update_count }} updates still missing.
|
||||
{% for update in updates %}
|
||||
- {{ update.title }}
|
||||
{% endfor %}
|
||||
vars:
|
||||
updates: "{{ (missing_updates.updates.values() | list) if (missing_updates.updates is mapping) else (missing_updates.updates) }}"
|
||||
when: missing_updates.updates is defined
|
||||
|
||||
@@ -72,7 +129,7 @@
|
||||
{{ (update_retry_limit | int) - (update_retry_count | int) }} more retries left'
|
||||
when:
|
||||
- missing_updates.found_update_count > 0
|
||||
- ((update_retry_limit | int) - (update_retry_count | int) >= 0)
|
||||
- ((update_retry_limit | int) - (update_retry_count | int) > 0)
|
||||
|
||||
rescue:
|
||||
- name: set update count
|
||||
@@ -80,7 +137,14 @@
|
||||
update_retry_count: '{{ update_retry_count | default(0) | int + 1 }}'
|
||||
|
||||
- debug:
|
||||
msg: "Still more updates remaining - retrying... ({{ update_retry_count }}/{{ update_retry_limit }})"
|
||||
msg: "Still more updates ({{ current_update_count }}) remaining - retrying... ({{ update_retry_count }}/{{ update_retry_limit }})"
|
||||
vars:
|
||||
current_update_count: "{{ missing_updates.found_update_count | default(installed_updates.found_update_count) | default('-') }}"
|
||||
|
||||
- name: ensure system is reachable
|
||||
wait_for_connection:
|
||||
sleep: 10
|
||||
timeout: 600
|
||||
|
||||
- include_tasks: updates-with-retry.yml
|
||||
when: ((update_retry_limit | int) - (update_retry_count | int) >= 0)
|
||||
when: ((update_retry_limit | int) - (update_retry_count | int) > 0)
|
||||
Reference in New Issue
Block a user