Windows Automation with Ansible: Getting Started Guide
Overview
In this article we will focus on how to get started with automation of windows using Ansible. Specifically we will look at installing 3rd party software and OS updates. Automation is the basis for cloud-computing or cloud-native patterns and breeds a culture of innovation. Let's face it, we cannot innovate, if we are stuck doing mundane tasks and manual labor. Ansible has revolutionized automation because until Ansible, automating was rather complicated and required lots of domain knowledge. Ansible provides an automation language that the entire organization can use because it is so easy and so flexible. The best thing about Ansible though it it brings teams together and fosters a devops culture. It brings the Linux and Windows world together!
How Ansible Works
Ansible provides a runtime for executing playbooks. A playbook is simply a group of plays which are essentially steps executed in order. A play is one or more tasks. A task is simply the execution of an Ansible module. An Ansible module is python code that does something, like install a software package, update the system, change a configuration file, check if something is set correctly, etc. There are 1000s of Ansible modules and a huge community around it.
In order to run a playbook against hosts you need an inventory which is simply a grouping of hosts and host vars (parameters). That is about it for the basics. Below is a diagram showing the Ansible automation engine architecture.
This guide assumes you know some Ansible or are familar with the basics. If not I created an Ansible getting started guide here. I highly recommend giving it a look before proceeding.
Prerequisites
In order for a windows host to be managed by Ansible there are a few prerequisites
- Powershell version 3.0 or higher (Should be fine with Windows 2012 or higher)
- .NET Framework 4.0 or higher (should be fine with Windows 2012 or higher)
- Windows Remote Management Listener or SSH (cygwin)
- Windows 7, 8.1, and 10, and server OSs including Windows Server 2008, 2008 R2, 2012, 2012 R2, 2016, and 2019
- Chocolatey for installing 3rd party software
- WSUS for updating OS packages and patching
Install Chocalatey and WSUS
There are various tools that can be used. I recommend using Chocolatey for installing packages and WSUS for OS updates/patching.
Install Chocalately
Using powershell we can install chocalately.
PS C:\windows\system32> Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Install WSUS
Open server manager. In the top right under manage you can add or change roles.
Under server roles select Windows Service Update Services. This will install WSUS. Once installed there will be a WSUS option in server manager. You can select it and configure what packages should be updated, etc.
Open WSUS and check that the computer is showing up under 'All Computers'. If not and you are running outside of domain you may need the following fix.
c:\> net stop wuauserv c:\> regsvr32 /s wuapi.dll c:\> regsvr32 /s wups.dll c:\> regsvr32 /s wuaueng.dll c:\> regsvr32 /s wucltui.dll c:\> regsvr32 /s msxml3.dll c:\> cd %windir%\SoftwareDistribution c:\> rd /s/q DataStore c:\> mkdir DataStore c:\> rd /s/q Download c:\> mkdir Download c:\> net start wuauserv c:\> reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate /v AccountDomainSid /f c:\> reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate /v PingID /f c:\> reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate /v SusClientId /f c:\> wuauclt /resetauthorization c:\> wuauclt /detectnow c:\> wuauclt /reportnow
Configuring Windows Remote Management for Ansible
Ansible requires no agents. It uses what the OS provides for communication. In Windows you can use SSH or Windows Remote Management (WinRM). Since SSH is more or less bolted on, WinRM is usually the preferred choice.
Test to ensure WinRM is working
First install WinRM if it isn't installed. Execute the hostname command through WinRM.
PS C:\windows\system32> winrs -r:http://:5985/wsman -u: -p: hostname win2012
Optionally you can also test WinRM by making a remote desktop connection from another windows host.
Note: you may run into an issue where you get an authentication error and a CredSSL issue if you have an older windows version. This can also happen if you don't have a valid SSL certificate. If you run into this issue, update your registry.
c:\>reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters" /f /v AllowEncryptionOracle /t REG_DWORD /d 2
Enable basic auth
There are several authentication methods. In this example we will use basic authentication which is username/password. This is of course the least secure method.
PS C:\> Set-Item -Path WSMan:\localhost\Service\Auth\Basic -Value $true
Update WinRM
A script is provided by Ansible community to check WinRM and make necessary changes to allow Ansible to connect. In this case we are using basic authentication but likely you will want to use something more secure. The script can be found here and other authentication options are documented in the script header.
Open a powershell command prompt.
Store URL path to script.
PS C:\> $url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
Store location for the script
PS C:\> $file = "$env:temp\ConfigureRemotingForAnsible.ps1"
Download script and output to file locally.
PS C:\> (New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
Execute the script.
PS C:\> powershell.exe -ExecutionPolicy ByPass -File $file Ok.
Check WinRM connection
PS C:\windows\system32> winrm enumerate winrm/config/Listener Listener Address = * Transport = HTTP Port = 5985 Hostname Enabled = true URLPrefix = wsman CertificateThumbprint ListeningOn = 10.10.1.139, 127.0.0.1, ::1, fe80::5efe:10.10.1.139%22, fe80::8155:327a:aeaf:365a%12 Listener Address = * Transport = HTTPS Port = 5986 Hostname Enabled = true URLPrefix = wsman CertificateThumbprint = 7a38de2c212764a54de106dc756f7cbc275156a3 ListeningOn = 10.10.1.139, 127.0.0.1, ::1, fe80::5efe:10.10.1.139%22, fe80::8155:327a:aeaf:365a%12
Ensure the HTTP/HTTPS ports are open.
More details about WinRM setup and how to setup a listener manually are documented here. In this case I used the default listener configured by WinRM.
Create Inventory File
We will create an inventory file with just a single host in a group called windows. From here on out we will be working on a Linux server where we have Ansible installed.
Create Ansible inventory file
$ vi inventory [windows] 138.204.12.111
Test ansible connection
Using the inventory file we can test if Ansible can communicate with our windows server.
$ ansible -i ../inventory windows -m win_ping -e ansible_connection=winrm \ -e ansible_user=Admin -e ansible_password=<password> \ -e ansible_winrm_transport=basic \ -e ansible_winrm_server_cert_validation=ignore 138.201.147.202 | SUCCESS => { "changed": false, "ping": "pong" }
Windows Patch Management
Now that Ansible is working with WinRM we can automate. In this case we will automate software package installation and updates.
Playbook and roles are available here.
Create Playbook
We haven't talked about roles. In Ansible roles are how we make playbooks reusable. It is always good practice to create roles. A role essentially allows you to organize Ansible plays and their dependencies together allowing them to be consumed easily. In order to use roles you need to create a certain directory structure and hierarchy. Create a playbook that imports our roles.
$ vi windows_baseline.yaml --- - name: Windows Baseline hosts: "" connection: winrm gather_facts: true vars: ansible_user: "" ansible_password: "" ansible_connection: winrm ansible_winrm_transport: basic ansible_winrm_server_cert_validation: ignore tasks: - name: Install Baseline Packages include_role: name: install - name: Perform Updates include_role: name: updates
Here we are setting hosts, ansible user and password as variables. These inputs must be provided when executing the playbook. Hosts should be the name of our host group from our inventory file. This playbook has two tasks, a role to install packages and a role to do an OS update.
Create Ansible install role
At a minimum your role will need a tasks directory
$ mkdir -p roles/install/tasks
Create a task to install git using the chocalatey module.
$ vi roles/install/tasks/main.yaml --- - name: Install Git win_chocolatey: name: git state: present
Create Ansible patch update role
At a minimum your role will need a tasks directory
$ mkdir -p roles/updates/tasks
Create a task to perform an OS update.
vi roles/updates/tasks/main.yaml --- - name: Update windows packages win_updates: category_names: - CriticalUpdates - SecurityUpdates reboot: yes reboot_timeout: 500
Run playbook using inventory
The '-vvvvv' allows the playbook to run in debug mode for maximum verbosity.
$ ansible-playbook -i ./inventory -e target=windows -e user=Admin -e password= windows_baseline.yaml PLAY [Windows Baseline] **************************************************************************** TASK [Gathering Facts] ***************************************************************************** ok: [138.201.147.202] TASK [Install Baseline Packages] ******************************************************************* TASK [install : Install Git] *********************************************************************** ok: [138.201.147.202] TASK [Perform Updates] ***************************************************************************** TASK [updates : Update windows packages] *********************************************************** changed: [138.201.147.202] PLAY RECAP ***************************************************************************************** 138.201.147.202 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=
Here are some additional examples of windows playbooks that may be of interest on your journey.
Summary
In this article we discussed the value of automation and why it is just a game changer. We provided a step-by-step on preparing a windows host for Ansible. Finally using the Ansible automation language, showed how to use native windows tooling to install and update OS patches. Hopefully this will provide a good starting point for a journey into windows automation with Ansible.
(c) 2020 Keith Tenzer