├── .ansible-lint ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .yamllint ├── LICENSE ├── README.md ├── defaults └── main.yml ├── meta └── main.yml ├── tasks └── main.yml └── tests ├── inventory └── test.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | warn_list: 4 | - role-name 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | github: deekayen 4 | ko_fi: deekayen 5 | liberapay: deekayen 6 | custom: ["paypal.me/deekayen", "venmo.com/drdnorman", "buymeacoff.ee/deekayen"] 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: CI 4 | 'on': 5 | pull_request: 6 | push: 7 | branches: 8 | - main 9 | 10 | defaults: 11 | run: 12 | working-directory: 'deekayen.win_updates' 13 | 14 | jobs: 15 | 16 | lint: 17 | name: Lint 18 | runs-on: ubuntu-20.04 19 | steps: 20 | - name: Check out the codebase. 21 | uses: actions/checkout@v2 22 | with: 23 | path: 'deekayen.win_updates' 24 | 25 | - name: Install test dependencies. 26 | run: python -m pip install --user ansible ansible-lint 27 | 28 | - name: Lint ansible. 29 | run: ansible-lint 30 | 31 | syntax: 32 | name: Syntax check 33 | runs-on: ubuntu-20.04 34 | steps: 35 | - name: Check out the codebase. 36 | uses: actions/checkout@v2 37 | with: 38 | path: 'deekayen.win_updates' 39 | 40 | - name: Install test dependencies. 41 | run: python -m pip install --user ansible 42 | 43 | - name: Create ansible.cfg with correct roles_path 44 | run: printf '[defaults]\nroles_path=../' >ansible.cfg 45 | 46 | - name: Check syntax. 47 | run: ansible-playbook tests/test.yml -i tests/inventory --syntax-check 48 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Release 4 | 'on': 5 | push: 6 | tags: 7 | - '*' 8 | 9 | defaults: 10 | run: 11 | working-directory: 'deekayen.win_updates' 12 | 13 | jobs: 14 | 15 | release: 16 | name: Release 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Check out the codebase. 20 | uses: actions/checkout@v2 21 | with: 22 | path: 'deekayen.win_updates' 23 | 24 | - name: Set up Python 3. 25 | uses: actions/setup-python@v2 26 | with: 27 | python-version: '3.x' 28 | 29 | - name: Install Ansible. 30 | run: pip3 install ansible-base 31 | 32 | - name: GitHub Environment Variables Action 33 | uses: FranzDiebold/github-env-vars-action@v2.3.0 34 | 35 | - name: Trigger a new import on Galaxy. 36 | run: ansible-galaxy role import --branch $CI_REF_NAME --api-key ${{ secrets.GALAXY_API_KEY }} $CI_REPOSITORY_OWNER $CI_REPOSITORY_NAME 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.keytab 2 | *.retry 3 | .DS_Store 4 | .DS_Store? 5 | ._* 6 | .Spotlight-V100 7 | .Trashes 8 | ehthumbs.db 9 | Thumbs.db 10 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | repos: 4 | - repo: https://github.com/ansible/ansible-lint.git 5 | rev: v5.0.12 6 | hooks: 7 | - id: ansible-lint 8 | files: \.(yaml|yml)$ 9 | args: [--exclude=/Users/deekayen/.ansible] 10 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | extends: default 4 | 5 | rules: 6 | indentation: 7 | spaces: 2 8 | indent-sequences: whatever 9 | line-length: disable 10 | truthy: disable 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2016, David Norman 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Windows Updates 2 | =============== 3 | [![CI](https://github.com/deekayen/ansible-role-win_updates/actions/workflows/ci.yml/badge.svg)](https://github.com/deekayen/ansible-role-win_updates/actions/workflows/ci.yml) [![Platforms](http://img.shields.io/badge/platforms-windows-lightgrey.svg?style=flat)](#) [![Project Status: Inactive – The project has reached a stable, usable state but is no longer being actively developed; support/maintenance will be provided as time allows.](https://www.repostatus.org/badges/latest/inactive.svg)](https://www.repostatus.org/#inactive) 4 | 5 | Install Microsoft Windows updates. 6 | 7 | Requirements 8 | ------------ 9 | 10 | The target Windows machines must have whitelisted network access to download updates. 11 | 12 | Role Variables 13 | -------------- 14 | 15 | By default, this role installs the default categories of updates provided by the Ansible [win_updates](http://docs.ansible.com/ansible/win_updates_module.html) module. Change `win_updates_category_names` to install alternate categories of updates. 16 | 17 | Not all updates request to reboot after installation, but they do tell Ansible when a reboot is required to complete the install. Toggle the `win_updates_reboot` variable to `true` to reboot when updates request a reboot. 18 | 19 | Dependencies 20 | ------------ 21 | 22 | None. 23 | 24 | Example Playbook 25 | ---------------- 26 | 27 | - hosts: servers 28 | roles: 29 | - role: deekayen.win_updates 30 | win_updates_reboot: true 31 | win_updates_category_names: 32 | - "CriticalUpdates" 33 | - "SecurityUpdates" 34 | 35 | License 36 | ------- 37 | 38 | BSD 39 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | win_updates_category_names: ['CriticalUpdates', 'SecurityUpdates', 'UpdateRollups'] 4 | win_updates_reboot: false 5 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | galaxy_info: 4 | role_name: win_updates 5 | namespace: deekayen 6 | author: David Norman 7 | description: Install Microsoft Windows updates. 8 | license: BSD 9 | min_ansible_version: 2.0 10 | 11 | github_branch: main 12 | issue_tracker_url: https://github.com/deekayen/ansible-role-win_updates/issues 13 | 14 | platforms: 15 | - name: Windows 16 | versions: 17 | - all 18 | 19 | galaxy_tags: 20 | - windows 21 | - security 22 | 23 | dependencies: [] 24 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install Windows updates. 4 | win_updates: 5 | category_names: "{{ win_updates_category_names }}" 6 | register: win_updates_result 7 | failed_when: 8 | - win_updates_result.failed is defined 9 | - win_updates_result.failed 10 | - not win_updates_reboot 11 | 12 | - block: 13 | # Attempting some error handling. 14 | - name: Reboot Windows to re-try update installation. 15 | win_reboot: 16 | shutdown_timeout_sec: 3600 17 | reboot_timeout_sec: 3600 18 | # Let it fail this time if reboot didn't work. 19 | when: 20 | - win_updates_result.error is defined 21 | - win_updates_result.error == "A reboot is required before more updates can be installed." 22 | 23 | - name: Install Windows updates again. 24 | win_updates: 25 | category_names: "{{ win_updates_category_names }}" 26 | register: win_updates_result 27 | 28 | when: 29 | - win_updates_reboot 30 | - win_updates_result.failed is defined 31 | - win_updates_result.failed 32 | 33 | - name: Reboot when updates installed. 34 | win_reboot: 35 | shutdown_timeout_sec: 3600 36 | reboot_timeout_sec: 3600 37 | when: 38 | - win_updates_result.reboot_required is defined 39 | - win_updates_result.reboot_required 40 | register: reboot_status 41 | 42 | - name: Print the update summary. 43 | debug: 44 | msg: | 45 | {{ win_updates_result.installed_update_count }} updates were installed on {{ inventory_hostname }}. 46 | The updates installed were: 47 | 48 | {% for key, value in win_updates_result.updates.iteritems() %} 49 | - {{ value.title }} 50 | {% endfor %} 51 | {{ win_updates_result.failed_update_count }} updates failed to install. 52 | It took {{ reboot_status.elapsed / 60 }} minutes for the machine to reboot. 53 | -------------------------------------------------------------------------------- /tests/inventory: -------------------------------------------------------------------------------- 1 | localhost 2 | 3 | -------------------------------------------------------------------------------- /tests/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | remote_user: root 5 | 6 | roles: 7 | - deekayen.win_updates 8 | --------------------------------------------------------------------------------