Patching windows servers with Ansible

64 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 64 Email -- 64 Flares ×

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:

# windows-updates-all.yml

 
– hosts: domain_controllers
  serial: 1
  remote_user: administrator@SKUNKWORKS.LOCAL
 
  tasks:
 
   # Check if there are missing updates
    – block:
        – name: Check for missing updates.
          win_updates: state=searched
          register: update_count
 
    #Install missing updates only if at least one is missing
    – block:
        – name: Install missing updates.
          win_updates:
            category_names:
              – Application
              – Connectors
              – DefinitionUpdates
              – DeveloperKits
              – FeaturePacks
              – Guidance
              – ServicePacks
              – Tools
              – UpdateRollups
              – CriticalUpdates
              – SecurityUpdates
          register: update_result
        – name: Reboot, if needed.
          win_reboot:
          when: update_result.reboot_required
      when: update_count.found_update_count|int >= 1

 

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:

Patch00

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:

Patch01

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:

Patch03

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:

Patch05

64 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 64 Email -- 64 Flares ×
  • YEON KI KIM

    Can you show update whole relation playbook script ?

  • c0mputernick

    Is it possible to schedule the reboot via task scheduler instead of immediate reboot or maybe Ansible already has something built in for this? I would like to try this out, but patch during the day and schedule the reboots to happen at night. Thanks for the help.

    • Hi,
      yes, you can remove the lines related to the reboot option so that the playbook will only install the patches. You can plan for another playbook that runs for example weekly, checks if a machine has a pending reboot, and executes it.

  • How to do for non-domain windows machines ? How entry should be in kerberos files ?

    • Hi, for local accounts you can use again WinRM, but this time with NTLM instead of Kerberos.