After I configured my Ansible server to manage my windows machines in the previous article, one of the first tasks I planned to automate was patching. Patching is one of those extremely boring but needed activities, and in any environment, even with a small amount of server, automated patching may be a savior. As long as proper data protection is in place, like a daily backup of the involved virtual machines, we can safely plan automatic updates, and if anything goes wrong, we just need to revert the virtual machine to the previous state. As an alternative, you can use for example Veeam Quick Backup, automated again via Ansible and Powershell (Start-VBRQuickBackup) as a pre-task in the playbook, so that everytime a patching activity is initiated, Ansible requests first to Veeam server to make a Quick Backup of the virtual machines.
1. select the hosts
In my Ansible hosts file, I have a dedicated group for my domain controllers:
[domain_controllers] dc01.skunkworks.local dc02.skunkworks.local
Thanks to this, in my playbook I can use the [domain_controllers] group to run it only against this group and not every server I’m managing.
2. write the playbook
A playbook in Ansible is a list of tasks that will be executed against one or more managed servers. This is my playbook:
Let’s explain it a little bit. Note first of all that the block option is a new feature in Ansible 2.0, it’s not recognized in Ansible 1.x. At the beginning, I select the domain controllers as the target of this playbook. If you want to check which servers will be processed, you can do like this:
[root@ansible playbooks]# ansible-playbook windows-updates-all.yml --list-hosts playbook: windows-updates-all.yml play #1 (domain_controllers): domain_controllers TAGS:  pattern: [u'domain_controllers'] hosts (2): dc01.skunkworks.local dc02.skunkworks.local
Then, serial: 1 means that the playbook will only process one server at a time. With this option one of my two domain controllers will always be up and running while the other one is processed, so that Active Directory and DNS services will always be available in my network.
win_updates is an Ansible module that run windows update in a Windows machine. The categories are all the existing update categories in Windows Update, and I selected them all. I first run a check for missing updates, if the count is more than 0, it means there is at least one missing update, and the playbook proceed; otherwise, we skip the rest of the playbook and move to the next server. During the patching activity I register the result in the variable update_result. One of the information is a pending reboot condition; if a patch requires a reboot, the second task executes a reboot of the windows machine, using another Ansible module, win_reboot.
3. Run the playbook
You can choose to run the playbook immediately as it is, or you can test it against a single host to verify it. This is what I’ve done first:
The syntax is ansible-playbook -l host playbook.yml. As you can see from the screen capture, Ansible has identified the hosts (when I did this first test I still had 3 hosts in my list), verified that there are patches to be installed and did it (changed equals 1, which means that 1 server out of 4 has been changed) and I’ve seen that the server has been rebooted too. Looking at the Windows Event Viewer, I see that patches have been installed:
4. Unleash the playbook
Once we have verified that the playbook is correct, we can plan to run it against both domain controllers, and obviously schedule it too:
You can see in this case, dc01 is completely patched, so it has been skipped: dc02 had an issue as one of the patches failed to be downloaded. In my case, the error was caused by lack of disk space in the C: drive of dc02, after cleaning the disk and have enough free space, the server has been successfully patched. Once the error is fixed, you can decide to re-run the playbook, or if you schedule it you can simply wait for its next execution, and eventually all the patches will be installed and your servers will be all up to date.
Just remember, Windows Updates takes sometimes even several hours, so let the playbook run and check back later, it may take a long time to complete. Also, I didn’t have time yet to manage one condition that can break the playbook, that is when a server already had a pending reboot that doesn’t allow Windows Update to run. If I’ll find something, I’ll update the script.
Finally, a trick: if you want to know how many updates are missing (the same value I used to initiate the patching task), you can run (after the check task) this line: debug: var=update_count, and the line found_update_count will tell you the number for each server: