Automate Windows Server with Ansible (example Windows Updates)

It doesn't always have to be SCCM... I was looking for a way to automate as many of my boring tasks as possible for my own systems: Backing up or mirroring the website to the NAS, installing updates (Windows / Linux), installing test environments. Just repetitive, boring, time-consuming stuff, made for automation and central control. After a few tests, I ended up using Ansible to automate as many tasks as possible. In the meantime (admittedly after a few failures) things are running smoothly, so here is a brief introduction to the topic of automation using Ansible. As it was my first use case, I chose the topic of Windows updates for the first example.

CentOS 8 Installation

I normally use Debian for most of my Linux-based servers, but recently I've taken a liking to CentOS. I'm currently migrating my private systems from Debian to CentOS, so this article also uses CentOS as the operating system for Ansible (in case anyone is wondering why I'm not using Debian).

The installation of CentOS is self-explanatory, so here are just a few screenshots of my setup:

CentOS 8 Installation

Since I run CentOS as a VM, I have selected "Server" and "Guest agents":

CentOS 8 Installation

The root password can be set and a user created during installation:

CentOS 8 Installation

After a few minutes CentOS is installed:

CentOS 8 Installation

After the installation, only an IP address and DNS server, as well as time synchronization via NTP were configured. Once the CentOS installation is complete, Ansible can be installed.

Ansible installation

PIP (python installs packages) can be used for the Ansible installation. For this to work, Python must first be installed. Python can be installed using the following commands:

1
sudo dnf install python3 python3-pip python3-devel

Ansible installation

After Python, Ansible can be installed with the following command:

1
sudo pip3 install ansible

Ansible installation

Incidentally, I deliberately carried out the installation via PIP. When installing Ansible via the normal CentOS repo, I did not manage to get all components running successfully. When the installation was done via PIP, I had no problems.

Ansible is already installed, but the PyWinRM package is required so that Windows servers can also be managed later using WinRM. The package can be installed with the following command:

1
sudo pip3 install pywinrm

Ansible installation

Once Ansible has been installed, you can continue with the basic configuration.

Ansible basic configuration

As the installation of Ansible was carried out using PIP, two basic files for the configuration of Ansible are still missing. However, the required files can simply be downloaded and created in the corresponding directory. Ansible then loads these files at runtime.

The following commands can be used to create the directory and download the configuration files:

1
2
3

Ansible basic configuration

The ansible.cfg file does not need to be adapted initially. The servers to be managed are specified later in the "hosts" file.

Ansible authentication using Kerberos

The administration of Windows servers with Ansible would already work using WinRM, but currently only with a local user on the respective server. However, the use of Active Directory user accounts and authentication via Kerberos is the more elegant way here, especially as the management of some services on Windows servers only works with Active Directory users (the automation of Exchange servers would be an example here).

In order for Ansible to log on to Windows servers using AD users and Kerberos, a few more packages need to be installed.

1
sudo dnf install gcc krb5-devel krb5-libs krb5-workstation

Ansible authentication using Kerberos

The connection to the Active Directory must now be configured in the /etc/krb5.conf file. In the file, the domain controller is entered in the "realms" section and the name of the Active Directory in the "domain_realm" section.

In my test environment, for example, this looks like this (case-sensitive):

Ansible authentication using Kerberos

The following command can now be used to test whether authentication using Kerberos works:

1
kinit Administrator @FRANKYSWEBLAB .EN

If the command does not return an error message, everything is OK. The "klist" command can also be used to check whether a Kerberos ticket has been issued:

Ansible authentication using Kerberos

Finally, the Kerberos support for PyWinRM must be installed:

1
sudo pip3 install pywinrm [kerberos]

Ansible authentication using Kerberos

Ansible can now also use Active Directory users and Kerberos for authentication on the Windows server.

Create groups and hosts

Servers that are to be managed via Ansible must be made known in the file /etc/ansible/hosts. Individual servers can be combined into host groups within the file. Here is an example of my /etc/ansible/hosts file:

Create groups and hosts

For example, the file contains the group "exchangeserver". The servers ex1 and ex2 are members of the exchangeserver group (first box in the screenshot). In the second box you will find the environment variables for the group, for the sake of simplicity I have also stored the login information here. There is also the group "windowsserver", this group contains all host groups with Windows systems:

Create groups and hosts

I have summarized the relevant files as a download at the end of the article. So if someone wants to rebuild this, not everything has to be typed out here.

Configure Windows systems

In order for Ansible to access the Windows servers via WinRM, WinRM must be configured accordingly. The configuration of WinRM is very easy thanks to a PowerShell script. The script can be downloaded here:

The script must be executed as an administrator on every Windows server that is to be managed using Ansible.

Configure Windows systems

The script creates a self-signed certificate and configures WinRM accordingly. The connection from the Ansible server to the Windows server is made via port 5986, the Windows firewall is configured automatically, if other firewalls are used, they must allow communication via port 5986.

Test connection

The preparations are now complete and you can test whether Ansible can establish a connection to the configured Windows servers. The following command can be used to test the connection:

1
ansible GROUP NAME -m win_ping

This command executes the module win_ping (WinRM based test) for the members of a group:

Test connection

The screenshot shows how the individual groups can be tested. If there are any problems here, the first thing to check is whether the servers are resolved via DNS and the login information is correct. If the connection is successful, you can create your first playbook.

Create playbook for Windows updates

Playbooks are used to execute a sequence of actions on the target systems. In this section, a simple playbook is created for the installation of Windows updates. This playbook only serves as an example for the time being, but if you familiarize yourself a little with Ansible, you can quickly implement more complex things here.

First, a directory structure can be created for the playbooks, making it easier to find the playbooks later. In this example, the directory "ansible-playbooks" and the subdirectory "windows" are created. All playbooks for Windows systems can then be saved in the "windows" folder. The directory structure is of course freely selectable here:

1
2
mkdir /ansible_playbooks
mkdir /ansible_playbooks/windows

The first playbook can now be created in the "windows" folder. In this example, the playbook is used to install Windows updates on the Windows servers:

1
touch /ansible_playbooks/windows/install_updates.yaml

The first playbook will have the following content:

Create playbook for Windows updates

The first step installs Windows updates on servers in the "fileserver" group (hosts: fileserver). If there are several hosts in the fileserver group, the updates are installed in parallel on the servers (strategy: free). The task defines which action is to be carried out. In this case, critical and security updates are installed and the servers are restarted if necessary. In the next step, it is the domain controllers' turn, followed by the hosts in the "exchange servers" group.

This simple playbook is just a small example. If you familiarize yourself with it a little, you can automate many things using Ansible. This example can also be downloaded at the end of the article.

For example, I have automated the update process for my private environment, which then runs as follows:

  1. Create VMware snapshots for all virtual servers that require updates
  2. Installing updates on Windows and Linux servers
  3. Restart the servers if this is necessary
  4. Send e-mail notification
  5. Delete snapshot 2 days later

The download at the end of the article also contains an example of how an Exchange DAG can be updated.

Run playbook

Previously created playbooks can be executed with the command "ansible-playbook". In this example, the previously created playbook is executed:

1
ansible-playbook install_updates.yml

Ansible now executes the steps from the playbook on the servers:

Run playbook

As you can see in the screenshot above, one command is now sufficient to provide all Windows servers with updates in the appropriate order. Several different systems can also be addressed within the playbook. For example, an Exchange server can be taken from the load balancer pool first and only then updated, or a snapshot could be created first, or or or or...

Download

As promised, the download with the corresponding examples can be found here:

The files included are for example purposes only and must be adapted to your own environment. Perhaps the examples will make it easier for some of you to get started with Ansible.

Conclusion

After a bit of familiarization and a lot of testing, you get used to Ansible quite quickly. The ability to automate almost all systems offers enormous potential. After all, you can not only execute actions on Windows and Linux servers, but also control almost every other device in the network (switches, routers, firewalls, load balancers, hypervisors, "the sheet metal", air conditioning systems, access control, databases, etc., etc., etc.) and it doesn't end with your own network, you can also control the interfaces of Azure, AWS and GCP. So the possibilities are pretty diverse...

Tip: There is also a graphical front end for Ansible:

12 thoughts on “Windows Server mit Ansible automatisieren (Beispiel Windows Updates)”

  1. Wäre es denkbar das Thema hier mal nochmals zu vertiefen?

    WIr haben selbst nun eine Ansible AWX + GitLab Lösung, die unsere Windows + Linuxumgebung patcht/konfiguriert.
    Unter Windows nutzen wir Zertifikate + CredSSP per WinRM.

    Das ganze funktioniert SUPER!

    Natürlich muss man sich mit Ansible und den vielen Modulen beschäftigen und ausprobieren…
    Aber die Möglichkeiten sind unendlich..

    Vmware Guest Tools aktualisieren
    Windows Dienste vorher beenden, Downtime in einer Überwachungslösung setzen, Server neustarten, alle dienste wieder starten, Downtime wieder beenden.

    Windows Patche einspiele
    Windows Features aktivieren/Deaktivieren

    Konfigurationen global verteilen (DNS Änderung, NTP Zeitserver, RegKey…..)

    Verteilung von ThirdParty Software

    Leider ist es in dem Umfeld noch schwer, geeignete Schulungen zu finden, die den Fokus auch mal auf WINDOWS legen.

    Reply
  2. Hi,

    ich weiß der Post ist schon älter, aber auch mich würde das Playbook für die Snapshots interessieren.

    Danke für das echt tolle Tutorial.

    Gruß
    Susie

    Reply
  3. Tolles Tutorial, vielen danke!
    Mich würde noch interessieren, ob es bei einer Authentifizierung mittels (selbstsignierten) Zertifikat möglich ist, das Inventory File dynamisch zu gestalten?

    Aktuell kann ich nur auf einen Windows Host mittels Zertifikat zugreifen:
    ansible_winrm_cert_pem=/root/cert.pem
    ansible_winrm_cert_key_pem=/root/cert_key.pem

    Mein Ziel wäre es die Keys des Windows Host in eine externe Datenbank zu exportieren und diese später wiederrum im Inventory File zu nutzen.

    Gruß Julian

    Reply
  4. Tolles Tutorial, danke!
    Mich würde noch interessieren, wie du die E-Mail Benachrichtigung gelöst hast. Hast du dazu evtl. einen Tipp?
    Danke und Gruss

    Reply
  5. Hallo!

    SUPER Tutorial! Alles funktioniert, bis auf das Starten der Powershell CMDs, die ich von dem Download- exupdates.yml kopiert habe.
    Andere PS Scripts, die eine Datei auf dem Zielsystem anlegen, funktionieren
    Kann jemand helfen? Folgenden Fehler bekomme ich:

    TASK [Place DAG in maintanance mode] *******************************************
    fatal: [srvex01.meinedomäne]: FAILED! => {„changed“: true, „cmd“: „$ErrorActionPreference = ‚Stop’\nwrite-host \“Hallo Welt!\“\ntry {\nwrite-host \“Server: \“ $env:computername -backgroundcolor cyan\n$ExchangeServerName = $env:computername\nAdd-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn\n. $env:ExchangeInstallPath\\bin\\RemoteExchange.ps1\nConnect-ExchangeServer -auto -AllowClobber\n}\ncatch {\nwrite-error ‚Failed to connect to Exchange Server’\nexit 1\n}\ntry {\nSet-MailboxServer $ExchangeServerName -DatabaseCopyActivationDisabledAndMoveNow $True\n}\ncatch {\nwrite-error ‚Failed to set Exchange Server into Maintanance

    Original und modifizierte Version funktionieren nicht und ich bekomme auch keine Ausgabe auf meinem Ansible Server bzgl. write-host.

    Danke!

    Reply
    • Ich habe die Lösung gefunden:
      den Text zwischen durch Eure Daten ersetzen.

      $ExchangeServerName = $env:computername
      $username = „“
      $password = ConvertTo-SecureString „“ -AsPlainText -Force
      $psCred = New-Object System.Management.Automation.PSCredential -ArgumentList ($username, $password)
      $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$ExchangeServerName/PowerShell/ -Authentication Kerberos -Credential $psCred
      Import-PSSession $Session -AllowClobber -DisableNameChecking

      und dann funktioniert auch der Rest von Franky’s Script

      Reply
  6. Großartiges Tutorial!

    An der Lösung bzgl. VM Snapshot und Löschen im Nachgang wäre ich auch interessiert.

    Wobei mir ein bisschen mulmig wird, ist der Sicherheitsaspekt einer solchen Lösung. Gibt es bestimmte best practices zur Absicherung des genutzten Accounts? Ich denke ein Domänennutzer als lokaler Admin auf den verwalteten Systemen wäre ausreichend? Was könnte man darüber hinaus noch im Bereich Hardening unternehmen? Unterbindung des interactive Logon? Beschränkung der Anmeldezeiten? Hat sonst noch jemand gute Ideen zur Absicherung?

    Gruß

    Reply
  7. Danke für das Tutorial.
    Funktioniert prima.

    Du hast geschrieben, dass du vor deinen Updates noch automatisch ein Snapshot der betroffenen VMs machst.
    Könntest du das Playbook bzw. die Anleitung dafür auch posten?

    Reply
  8. Umfangreiches und tolles Tutorial. Vielen Dank.

    Eine Frage zu Ansible, wie sind die Erfahrungen hinsichtlich Zuverlässigkeit wenn es um WinRM Verbindungen geht von CentOS zu Windows Servern in der Domäne?
    Bei WinRM und Kerberos denke ich da an die vielen Updates und Umstellungen die MS da in letzter zeit gemacht hat und bis nächstes Jahr noch machen wird.. (LDAP Secure, Zero Netlogon Lücke, ….)
    Wäre „SSH“ da nicht „störungssicherer“?
    Und kann man mit etwaigen Addons Ansible auch zusätzlich zur einfachen Inventarisierung der Serverlandschaft heranziehen?
    Bin gerade auf der Suche nach einer Lösung.
    Im Idealfall eine zentrale Patchmanagementlösung inkl. Inventarisierung von Servern.
    Ein einfacher WSUS und händisches Updates installieren geht ab bestimmten RZ-Größen nicht mehr..

    Danke fürs Feedback – auch generell zu Ansible…

    Reply
  9. Sehr schönes Tutorial,
    allerdings empfehle ich gleich mit AWX zu arbeiten (die freie Variante von Tower). Es ist einfach komfortabler das alles über den Browser zu steuern anstatt immer per SSH zu arbeiten.
    Ich würde ungeachtet von AWX auch den Server gleich mit in die Domäne nehmen und dann mit Domain Usern arbeiten, unter CentOS 8 wäre das:
    sudo dnf install realmd sssd oddjob oddjob-mkhomedir adcli samba-common samba-common-tools krb5-workstation authselect-compat
    realm join example.com -U administrator
    sudo authselect select sssd with-mkhomedir
    sudo systemctl restart sssd
    Einzelne User das Anmelden erlauben:
    realm permit user1@example.com
    Oder über Gruppen:
    realm permit -g ‚irgend eine gruppe‘

    Dann kann man die User oder Gruppen auch noch in ein Sudoers file eintragen.
    Vorteil der ganzen Sache, da man die meisten Pakete sowieso braucht, das man sich einfach mit Domainuser anmelden kann und (bei Putty) auch kein Passwort abgefragt wird.

    Um das ganze mit AWX noch weiter zu „pimpen“ kann man die Scripte dann noch aus einem Git Repo beziehen. Dann ist das alles höchst komfortabel und revisionssicher.

    Reply

Leave a Comment