- Using Ansible and Windows¶
- Use Cases¶
- Installing Software¶
- Installing Updates¶
- Set Up Users and Groups¶
- Running Commands¶
- Choosing Command or Shell¶
- Argument Rules¶
- Creating and Running a Scheduled Task¶
- Path Formatting for Windows¶
- YAML Style¶
- Legacy key=value Style¶
- Developing Windows Modules¶
- Windows Support¶
- Windows: How Does It Work¶
- Installing on the Control Machine¶
- Active Directory Support¶
- Installing python-kerberos dependencies¶
- Installing python-kerberos¶
- Configuring Kerberos¶
- Testing a kerberos connection¶
- Troubleshooting kerberos connections¶
- Windows System Prep¶
- Getting to PowerShell 3.0 or higher¶
- What modules are available¶
- Developers: Supported modules and how it works¶
- Reminder: You Must Have a Linux Control Machine¶
- Windows Facts¶
- Windows Playbook Examples¶
- Windows Contributions¶
- Setting up a Windows Host¶
- Host Requirements¶
- WinRM Memory Hotfix¶
- WinRM Setup¶
- WinRM Listener¶
- Setup WinRM Listener¶
- Delete WinRM Listener¶
- WinRM Service Options¶
- Common WinRM Issues¶
- HTTP 401/Credentials Rejected¶
- HTTP 500 Error¶
- Timeout Errors¶
- Connection Refused Errors¶
- Failure to Load Builtin Modules¶
- Windows SSH Setup¶
- Installing Win32-OpenSSH¶
Using Ansible and Windows¶
When using Ansible to manage Windows, many of the syntax and rules that apply for Unix/Linux hosts also apply to Windows, but there are still some differences when it comes to components like path separators and OS-specific tasks. This document covers details specific to using Ansible for Windows.
Ansible can be used to orchestrate a multitude of tasks on Windows servers. Below are some examples and info about common tasks.
There are three main ways that Ansible can be used to install software:
Using the win_chocolatey module. This sources the program data from the default public Chocolatey repository. Internal repositories can be used instead by setting the source option.
Using the win_command or win_shell module to run an installer manually.
The win_chocolatey module is recommended since it has the most complete logic for checking to see if a package has already been installed and is up-to-date.
Below are some examples of using all three options to install 7-Zip:
Many installers do not properly pass back error information over WinRM. In these cases, if the install has been verified to work locally the recommended method is to use become.
Some installers restart the WinRM or HTTP services, or cause them to become temporarily unavailable, making Ansible assume the system is unreachable.
The win_updates and win_hotfix modules can be used to install updates or hotfixes on a host. The module win_updates is used to install multiple updates by category, while win_hotfix can be used to install a single update or hotfix file that has been downloaded locally.
The win_hotfix module has a requirement that the DISM PowerShell cmdlets are present. These cmdlets were only added by default on Windows Server 2012 and newer and must be installed on older Windows hosts.
The following example shows how win_updates can be used:
The following example show how win_hotfix can be used to install a single update or hotfix:
Set Up Users and Groups¶
Ansible can be used to create Windows users and groups both locally and on a domain.
The following is an example of creating local accounts and groups that can access a folder on the same host:
The modules win_domain_user and win_domain_group manages users and groups in a domain. The below is an example of ensuring a batch of domain users are created:
The win_command module is used to execute a command which is either an executable or batch file, while the win_shell module is used to execute commands within a shell.
Choosing Command or Shell¶
Here are some examples of using win_command and win_shell :
Each argument is delimited by a white space, which can either be a space or a tab.
A double quote preceded by a backslash \ is interpreted as just a double quote » and not as an argument delimiter.
Backslashes are interpreted literally unless it immediately precedes double quotes; for example \ == \ and \» == «
If an even number of backslashes is followed by a double quote, one backslash is used in the argument for every pair, and the double quote is used as a string delimiter for the argument.
If an odd number of backslashes is followed by a double quote, one backslash is used in the argument for every pair, and the double quote is escaped and made a literal double quote in the argument.
With those rules in mind, here are some examples of quoting:
For more information, see escaping arguments.
Creating and Running a Scheduled Task¶
WinRM has some restrictions in place that cause errors when running certain commands. One way to bypass these restrictions is to run a command through a scheduled task. A scheduled task is a Windows component that provides the ability to run an executable on a schedule and under a different account.
Ansible version 2.5 added modules that make it easier to work with scheduled tasks in Windows. The following is an example of running a script as a scheduled task that deletes itself after running:
The modules used in the above example were updated/added in Ansible version 2.5.
Path Formatting for Windows¶
Ansible allows two different styles of syntax; each deals with path separators for Windows differently:
When using the YAML syntax for tasks, the rules are well-defined by the YAML standard:
When using a normal string (without quotes), YAML will not consider the backslash an escape character.
You should only quote strings when it is absolutely necessary or required by YAML, and then use single quotes.
The YAML specification considers the following escape sequences:
\x.. – 2-digit hex escape
\u. – 4-digit hex escape
\U. – 8-digit hex escape
Here are some examples on how to write Windows paths:
This is an example which will fail:
This example shows the use of single quotes when they are required:
Legacy key=value Style¶
The legacy key=value syntax is used on the command line for ad-hoc commands, or inside playbooks. The use of this style is discouraged within playbooks because backslash characters need to be escaped, making playbooks harder to read. The legacy syntax depends on the specific implementation in Ansible, and quoting (both single and double) does not have any effect on how it is parsed by Ansible.
The Ansible key=value parser parse_kv() considers the following escape sequences:
\x.. – 2-digit hex escape
\u. – 4-digit hex escape
\U. – 8-digit hex escape
\N <. >– Unicode character by name
This means that the backslash is an escape character for some sequences, and it is usually safer to escape a backslash when in this form.
Here are some examples of using Windows paths with the key=value style:
Some things you cannot do with Ansible and Windows are:
Interact with the WinRM listeners
Because WinRM is reliant on the services being online and running during normal operations, you cannot upgrade PowerShell or interact with WinRM listeners with Ansible. Both of these actions will cause the connection to fail. This can technically be avoided by using async or a scheduled task, but those methods are fragile if the process it runs breaks the underlying connection Ansible uses, and are best left to the bootstrapping process or before an image is created.
Developing Windows Modules¶
Because Ansible modules for Windows are written in PowerShell, the development guides for Windows modules differ substantially from those for standard standard modules. Please see Windows module development walkthrough for more information.
An introduction to playbooks
Tips and tricks for playbooks
Windows specific module list, all implemented in PowerShell
Have a question? Stop by the google group!
#ansible IRC chat channel
© Copyright 2021 Red Hat, Inc. Last updated on Mar 11, 2021.
Windows: How Does It Work¶
As you may have already read, Ansible manages Linux/Unix machines using SSH by default.
Starting in version 1.7, Ansible also contains support for managing Windows machines. This uses native PowerShell remoting, rather than SSH.
Ansible will still be run from a Linux control machine, and uses the “winrm” Python module to talk to remote hosts.
No additional software needs to be installed on the remote machines for Ansible to manage them, it still maintains the agentless properties that make it popular on Linux/Unix.
Note that it is expected you have a basic understanding of Ansible prior to jumping into this section, so if you haven’t written a Linux playbook first, it might be worthwhile to dig in there first.
Installing on the Control Machine¶
On a Linux control machine:
Active Directory Support¶
If you wish to connect to domain accounts published through Active Directory (as opposed to local accounts created on the remote host), you will need to install the “python-kerberos” module on the Ansible control host (and the MIT krb5 libraries it depends on). The Ansible control host also requires a properly configured computer account in Active Directory.
Installing python-kerberos dependencies¶
Once you’ve installed the necessary dependencies, the python-kerberos wrapper can be installed via pip:
Kerberos is installed and configured by default on OS X and many Linux distributions. If your control machine has not already done this for you, you will need to.
Edit your /etc/krb5.conf (which should be installed as a result of installing packages above) and add the following information for each domain you need to connect to:
In the section that starts with
add the full domain name and the fully qualified domain names of your primary and secondary Active Directory domain controllers. It should look something like this:
and in the [domain_realm] section add a line like the following for each domain you want to access:
You may wish to configure other settings here, such as the default domain.
Testing a kerberos connection¶
If you have installed krb5-workstation (yum) or krb5-user (apt-get) you can use the following command to test that you can be authorised by your domain controller.
Note that the domain part has to be fully qualified and must be in upper case.
To see what tickets if any you have acquired, use the command klist
Troubleshooting kerberos connections¶
If you unable to connect using kerberos, check the following:
Ensure that forward and reverse DNS lookups are working properly on your domain.
To test this, ping the windows host you want to control by name then use the ip address returned with nslookup. You should get the same name back from DNS when you use nslookup on the ip address.
If you get different hostnames back than the name you originally pinged, speak to your active directory administrator and get them to check that DNS Scavenging is enabled and that DNS and DHCP are updating each other.
Ensure that the Ansible controller has a properly configured computer account in the domain.
Check your Ansible controller’s clock is synchronised with your domain controller. Kerberos is time sensitive and a little clock drift can cause tickets not be granted.
Check you are using the real fully qualified domain name for the domain. Sometimes domains are commonly known to users by aliases. To check this run:
If the domain name returned by klist is different from the domain name you requested, you are requesting using an alias, and you need to update your krb5.conf so you are using the fully qualified domain name, not its alias.
Ansible’s windows support relies on a few standard variables to indicate the username, password, and connection type (windows) of the remote hosts. These variables are most easily set up in inventory. This is used instead of SSH-keys or passwords as normally fed into Ansible:
In group_vars/windows.yml, define the following inventory variables:
Although Ansible is mostly an SSH-oriented system, Windows management will not happen over SSH ( yet ).
If you have installed the kerberos module and ansible_user contains @ (e.g. username@realm ), Ansible will first attempt Kerberos authentication. This method uses the principal you are authenticated to Kerberos with on the control machine and not «ansible_user«. If that fails, either because you are not signed into Kerberos on the control machine or because the corresponding domain account on the remote host is not available, then Ansible will fall back to “plain” username/password authentication.
When using your playbook, don’t forget to specify –ask-vault-pass to provide the password to unlock the file.
Test your configuration like so, by trying to contact your Windows nodes. Note this is not an ICMP ping, but tests the Ansible communication channel that leverages Windows remoting:
You’ll run this command again later though, to make sure everything is working.
Since 2.0, the following custom inventory variables are also supported for additional configuration of WinRM connections:
Windows System Prep¶
In order for Ansible to manage your windows machines, you will have to enable PowerShell remoting configured.
To automate setup of WinRM, you can run this PowerShell script on the remote machine.
Admins may wish to modify this setup slightly, for instance to increase the timeframe of the certificate.
On Windows 7 and Server 2008 R2 machines, due to a bug in Windows Management Framework 3.0, it may be necessary to install this hotfix http://support.microsoft.com/kb/2842230 to avoid receiving out of memory and stack overflow exceptions. Newly-installed Server 2008 R2 systems which are not fully up to date with windows updates are known to have this issue.
Windows 8.1 and Server 2012 R2 are not affected by this issue as they come with Windows Management Framework 4.0.
Getting to PowerShell 3.0 or higher¶
PowerShell 3.0 or higher is needed for most provided Ansible modules for Windows, and is also required to run the above setup script. Note that PowerShell 3.0 is only supported on Windows 7 SP1, Windows Server 2008 SP1, and later releases of Windows.
Looking at an Ansible checkout, copy the examples/scripts/upgrade_to_ps3.ps1 script onto the remote host and run a PowerShell console as an administrator. You will now be running PowerShell 3 and can try connectivity again using the win_ping technique referenced above.
What modules are available¶
Most of the Ansible modules in core Ansible are written for a combination of Linux/Unix machines and arbitrary web services, though there are various Windows modules as listed in the “windows” subcategory of the Ansible module index.
Browse this index to see what is available.
In many cases, it may not be necessary to even write or use an Ansible module.
In particular, the “script” module can be used to run arbitrary PowerShell scripts, allowing Windows administrators familiar with PowerShell a very native way to do things, as in the following playbook:
Note there are a few other Ansible modules that don’t start with “win” that also function, including “slurp”, “raw”, and “setup” (which is how fact gathering works).
Developers: Supported modules and how it works¶
Developing Ansible modules are covered in a later section of the documentation, with a focus on Linux/Unix. What if you want to write Windows modules for Ansible though?
For Windows, Ansible modules are implemented in PowerShell. Skim those Linux/Unix module development chapters before proceeding.
Windows modules live in a “windows/” subfolder in the Ansible “library/” subtree. For example, if a module is named “library/windows/win_ping”, there will be embedded documentation in the “win_ping” file, and the actual PowerShell code will live in a “win_ping.ps1” file. Take a look at the sources and this will make more sense.
Modules (ps1 files) should start as follows:
What modules you see in windows/ are just a start. Additional modules may be submitted as pull requests to github.
Reminder: You Must Have a Linux Control Machine¶
Note running Ansible from a Windows control machine is NOT a goal of the project. Refrain from asking for this feature, as it limits what technologies, features, and code we can use in the main project in the future. A Linux control machine will be required to manage Windows hosts.
Cygwin is not supported, so please do not ask questions about Ansible running from Cygwin.
Just as with Linux/Unix, facts can be gathered for windows hosts, which will return things such as the operating system version. To see what variables are available about a windows host, run the following:
Note that this command invocation is exactly the same as the Linux/Unix equivalent.
Windows Playbook Examples¶
Look to the list of windows modules for most of what is possible, though also some modules like “raw” and “script” also work on Windows, as do “fetch” and “slurp”.
Here is an example of pushing and running a PowerShell script:
Running individual commands uses the ‘raw’ module, as opposed to the shell or command module as is common on Linux/Unix operating systems:
And for a final example, here’s how to use the win_stat module to test for file existence. Note that the data returned by the win_stat module is slightly different than what is provided by the Linux equivalent:
Again, recall that the Windows modules are all listed in the Windows category of modules, with the exception that the “raw”, “script”, and “fetch” modules are also available. These modules do not start with a “win” prefix.
Windows support in Ansible is still very new, and contributions are quite welcome, whether this is in the form of new modules, tweaks to existing modules, documentation, or something else. Please stop by the ansible-devel mailing list if you would like to get involved and say hi.
Developing Modules How to write modules Playbooks Learning Ansible’s configuration management language List of Windows Modules Windows specific module list, all implemented in PowerShell Mailing List Questions? Help? Ideas? Stop by the list on Google Groups irc.freenode.net #ansible IRC chat channel
Setting up a Windows Host¶
This document discusses the setup that is required before Ansible can communicate with a Microsoft Windows host.
For Ansible to communicate to a Windows host and use Windows modules, the Windows host must meet these requirements:
Ansible can generally manage Windows versions under current and extended support from Microsoft. Ansible can manage desktop OSs including Windows 7, 8.1, and 10, and server OSs including Windows Server 2008, 2008 R2, 2012, 2012 R2, 2016, and 2019.
A WinRM listener should be created and activated. More details for this can be found below.
While these are the base requirements for Ansible connectivity, some Ansible modules have additional requirements, such as a newer OS or PowerShell version. Please consult the module’s documentation page to determine whether a host meets those requirements.
This is an example of how to run this script from PowerShell:
If running on Server 2008, then SP2 must be installed. If running on Server 2008 R2 or Windows 7, then SP1 must be installed.
Windows Server 2008 can only install PowerShell 3.0; specifying a newer version will result in the script failing.
The username and password parameters are stored in plain text in the registry. Make sure the cleanup commands are run after the script finishes to ensure no credentials are still stored on the host.
WinRM Memory Hotfix¶
When running on PowerShell v3.0, there is a bug with the WinRM service that limits the amount of memory available to WinRM. Without this hotfix installed, Ansible will fail to execute certain commands on the Windows host. These hotfixes should be installed as part of the system bootstrapping or imaging process. The script Install-WMF3Hotfix.ps1 can be used to install the hotfix on affected hosts.
The following PowerShell command will install the hotfix:
For more details, please refer to the Hotfix document from Microsoft.
Once Powershell has been upgraded to at least version 3.0, the final step is for the WinRM service to be configured so that Ansible can connect to it. There are two main components of the WinRM service that governs how Ansible can interface with the Windows host: the listener and the service configuration settings.
Details about each component can be read below, but the script ConfigureRemotingForAnsible.ps1 can be used to set up the basics. This script sets up both HTTP and HTTPS listeners with a self-signed certificate and enables the Basic authentication option on the service.
To use this script, run the following in PowerShell:
The ConfigureRemotingForAnsible.ps1 script is intended for training and development purposes only and should not be used in a production environment, since it enables settings (like Basic authentication) that can be inherently insecure.
The WinRM services listens for requests on one or more ports. Each of these ports must have a listener created and configured.
To view the current listeners that are running on the WinRM service, run the following command:
This will output something like:
In the example above there are two listeners activated; one is listening on port 5985 over HTTP and the other is listening on port 5986 over HTTPS. Some of the key options that are useful to understand are:
Transport : Whether the listener is run over HTTP or HTTPS, it is recommended to use a listener over HTTPS as the data is encrypted without any further changes required.
CertificateThumbprint : If running over an HTTPS listener, this is the thumbprint of the certificate in the Windows Certificate Store that is used in the connection. To get the details of the certificate itself, run this command with the relevant certificate thumbprint in PowerShell:
Setup WinRM Listener¶
There are three ways to set up a WinRM listener:
Using Group Policy Objects. This is the best way to create a listener when the host is a member of a domain because the configuration is done automatically without any user input. For more information on group policy objects, see the Group Policy Objects documentation.
Using PowerShell to create the listener with a specific configuration. This can be done by running the following PowerShell commands:
To see the other options with this PowerShell cmdlet, see New-WSManInstance.
When creating an HTTPS listener, an existing certificate needs to be created and stored in the LocalMachine\My certificate store. Without a certificate being present in this store, most commands will fail.
Delete WinRM Listener¶
To remove a WinRM listener:
The Keys object is an array of strings, so it can contain different values. By default it contains a key for Transport= and Address= which correspond to the values from winrm enumerate winrm/config/Listeners.
WinRM Service Options¶
There are a number of options that can be set to control the behavior of the WinRM service component, including authentication options and memory settings.
To get an output of the current service configuration options, run the following command:
This will output something like:
While many of these options should rarely be changed, a few can easily impact the operations over WinRM and are useful to understand. Some of the important options are:
Service\Auth\* : These flags define what authentication options are allowed with the WinRM service. By default, Negotiate (NTLM) and Kerberos are enabled.
Service\Auth\CbtHardeningLevel : Specifies whether channel binding tokens are not verified (None), verified but not required (Relaxed), or verified and required (Strict). CBT is only used when connecting with NTLM or Kerberos over HTTPS.
Service\CertificateThumbprint : This is the thumbprint of the certificate used to encrypt the TLS channel used with CredSSP authentication. By default this is empty; a self-signed certificate is generated when the WinRM service starts and is used in the TLS process.
Winrs\MaxShellRunTime : This is the maximum time, in milliseconds, that a remote command is allowed to execute.
Winrs\MaxMemoryPerShellMB : This is the maximum amount of memory allocated per shell, including the shell’s child processes.
To modify a setting under the Service key in PowerShell:
To modify a setting under the Winrs key in PowerShell:
If running in a domain environment, some of these options are set by GPO and cannot be changed on the host itself. When a key has been configured with GPO, it contains the text [Source=»GPO»] next to the value.
Common WinRM Issues¶
Because WinRM has a wide range of configuration options, it can be difficult to setup and configure. Because of this complexity, issues that are shown by Ansible could in fact be issues with the host setup instead.
One easy way to determine whether a problem is a host issue is to run the following command from another Windows host to connect to the target Windows host:
If this fails, the issue is probably related to the WinRM setup. If it works, the issue may not be related to the WinRM setup; please continue reading for more troubleshooting suggestions.
HTTP 401/Credentials Rejected¶
A HTTP 401 error indicates the authentication process failed during the initial connection. Some things to check for this are:
Verify that the credentials are correct and set properly in your inventory with ansible_user and ansible_password
Ensure that the user is a member of the local Administrators group or has been explicitly granted access (a connection test with the winrs command can be used to rule this out).
Make sure that the authentication option set by ansible_winrm_transport is enabled under Service\Auth\*
When using Basic or Certificate authentication, make sure that the user is a local account and not a domain account. Domain accounts do not work with Basic and Certificate authentication.
HTTP 500 Error¶
These indicate an error has occurred with the WinRM service. Some things to check for include:
Verify that the number of current open shells has not exceeded either WinRsMaxShellsPerUser or any of the other Winrs quotas haven’t been exceeded.
These usually indicate an error with the network connection where Ansible is unable to reach the host. Some things to check for include:
Make sure the firewall is not set to block the configured WinRM listener ports
Ensure that a WinRM listener is enabled on the port and path set by the host vars
Ensure that the winrm service is running on the Windows host and configured for automatic start
Connection Refused Errors¶
These usually indicate an error when trying to communicate with the WinRM service on the host. Some things to check for:
Check that the host firewall is allowing traffic over the WinRM port. By default this is 5985 for HTTP and 5986 for HTTPS.
Sometimes an installer may restart the WinRM or HTTP service and cause this error. The best way to deal with this is to use win_psexec from another Windows host.
Failure to Load Builtin Modules¶
If powershell fails with an error message similar to The ‘Out-String’ command was found in the module ‘Microsoft.PowerShell.Utility’, but the module could not be loaded. then there could be a problem trying to access all the paths specified by the PSModulePath environment variable. A common cause of this issue is that the PSModulePath environment variable contains a UNC path to a file share and because of the double hop/credential delegation issue the Ansible process cannot access these folders. The way around this problems is to either:
Remove the UNC path from the PSModulePath environment variable, or
Use an authentication option that supports credential delegation like credssp or kerberos with credential delegation enabled
See KB4076842 for more information on this problem.
Windows SSH Setup¶
Ansible 2.8 has added an experimental SSH connection for Windows managed nodes.
Use this feature at your own risk! Using SSH with Windows is experimental, the implementation may make backwards incompatible changes in feature releases. The server side components can be unreliable depending on the version that is installed.
The first step to using SSH with Windows is to install the Win32-OpenSSH service on the Windows host. Microsoft offers a way to install Win32-OpenSSH through a Windows capability but currently the version that is installed through this process is too old to work with Ansible. To install Win32-OpenSSH for use with Ansible, select one of these three installation options:
Manually install the service, following the install instructions from Microsoft.
Install the openssh package using Chocolatey: