Setting up a Windows Host

This document discusses the setup that is required before Ansible can communicate with a Microsoft Windows host.

Host Requirements

For Ansible to communicate to a Windows host and use Windows modules, theWindows host must meet the following requirements:

  • Ansible’s supported Windows versions generally match those under currentand extended support from Microsoft. Supported desktop OSs includeWindows 7, 8.1, and 10, and supported server OSs are Windows Server 2008,2008 R2, 2012, 2012 R2, and 2016.
  • Ansible requires PowerShell 3.0 or newer and at least .NET 4.0 to beinstalled on the Windows host.
  • A WinRM listener should be created and activated. More details for this can befound below.

Note

While these are the base requirements for Ansible connectivity, some Ansiblemodules have additional requirements, such as a newer OS or PowerShellversion. Please consult the module’s documentation pageto determine whether a host meets those requirements.

Upgrading PowerShell and .NET Framework

Ansible requires PowerShell version 3.0 and .NET Framework 4.0 or newer to function on older operating systems like Server 2008 and Windows 7. The base image does not meet thisrequirement. You can use the Upgrade-PowerShell.ps1 script to update these.

This is an example of how to run this script from PowerShell:

  1. $url = "https://raw.githubusercontent.com/jborean93/ansible-windows/master/scripts/Upgrade-PowerShell.ps1"
  2. $file = "$env:temp\Upgrade-PowerShell.ps1"
  3. $username = "Administrator"
  4. $password = "Password"
  5.  
  6. (New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
  7. Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force
  8.  
  9. # version can be 3.0, 4.0 or 5.1
  10. &$file -Version 5.1 -Username $username -Password $password -Verbose

Once completed, you will need to remove auto logonand set the execution policy back to the default of Restricted. You cando this with the following PowerShell commands:

  1. # this isn't needed but is a good security practice to complete
  2. Set-ExecutionPolicy -ExecutionPolicy Restricted -Force
  3.  
  4. $reg_winlogon_path = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
  5. Set-ItemProperty -Path $reg_winlogon_path -Name AutoAdminLogon -Value 0
  6. Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultUserName -ErrorAction SilentlyContinue
  7. Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultPassword -ErrorAction SilentlyContinue

The script works by checking to see what programs need to be installed(such as .NET Framework 4.5.2) and what PowerShell version is required. If a rebootis required and the username and password parameters are set, thescript will automatically reboot and logon when it comes back up from thereboot. The script will continue until no more actions are required and thePowerShell version matches the target version. If the username andpassword parameters are not set, the script will prompt the user tomanually reboot and logon when required. When the user is next logged in, thescript will continue where it left off and the process continues until no moreactions are required.

Note

If running on Server 2008, then SP2 must be installed. If running onServer 2008 R2 or Windows 7, then SP1 must be installed.

Note

Windows Server 2008 can only install PowerShell 3.0; specifying anewer version will result in the script failing.

Note

The username and password parameters are stored in plain textin the registry. Make sure the cleanup commands are run after the script finishesto 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 thatlimits the amount of memory available to WinRM. Without this hotfix installed,Ansible will fail to execute certain commands on the Windows host. Thesehotfixes should installed as part of the system bootstapping orimaging process. The script Install-WMF3Hotfix.ps1 can be used to install the hotfix on affected hosts.

The following PowerShell command will install the hotfix:

  1. $url = "https://raw.githubusercontent.com/jborean93/ansible-windows/master/scripts/Install-WMF3Hotfix.ps1"
  2. $file = "$env:temp\Install-WMF3Hotfix.ps1"
  3.  
  4. (New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
  5. powershell.exe -ExecutionPolicy ByPass -File $file -Verbose

WinRM Setup

Once Powershell has been upgraded to at least version 3.0, the final step is for theWinRM service to be configured so that Ansible can connect to it. There are twomain components of the WinRM service that governs how Ansible can interface withthe Windows host: the listener and the service configuration settings.

Details about each component can be read below, but the scriptConfigureRemotingForAnsible.ps1can be used to set up the basics. This script sets up both HTTP and HTTPSlisteners with a self-signed certificate and enables the Basicauthentication option on the service.

To use this script, run the following in PowerShell:

  1. $url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
  2. $file = "$env:temp\ConfigureRemotingForAnsible.ps1"
  3.  
  4. (New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
  5.  
  6. powershell.exe -ExecutionPolicy ByPass -File $file

There are different switches and parameters (like -EnableCredSSP and-ForceNewSSLCert) that can be set alongside this script. The documentationfor these options are located at the top of the script itself.

Note

The ConfigureRemotingForAnsible.ps1 script is intended for training anddevelopment purposes only and should not be used in aproduction environment, since it enables settings (like Basic authentication)that can be inherently insecure.

WinRM Listener

The WinRM services listens for requests on one or more ports. Each of these ports must have alistener created and configured.

To view the current listeners that are running on the WinRM service, run thefollowing command:

  1. winrm enumerate winrm/config/Listener

This will output something like the following:

  1. Listener
  2. Address = *
  3. Transport = HTTP
  4. Port = 5985
  5. Hostname
  6. Enabled = true
  7. URLPrefix = wsman
  8. CertificateThumbprint
  9. ListeningOn = 10.0.2.15, 127.0.0.1, 192.168.56.155, ::1, fe80::5efe:10.0.2.15%6, fe80::5efe:192.168.56.155%8, fe80::
  10. ffff:ffff:fffe%2, fe80::203d:7d97:c2ed:ec78%3, fe80::e8ea:d765:2c69:7756%7
  11.  
  12. Listener
  13. Address = *
  14. Transport = HTTPS
  15. Port = 5986
  16. Hostname = SERVER2016
  17. Enabled = true
  18. URLPrefix = wsman
  19. CertificateThumbprint = E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE
  20. ListeningOn = 10.0.2.15, 127.0.0.1, 192.168.56.155, ::1, fe80::5efe:10.0.2.15%6, fe80::5efe:192.168.56.155%8, fe80::
  21. ffff:ffff:fffe%2, fe80::203d:7d97:c2ed:ec78%3, fe80::e8ea:d765:2c69:7756%7

In the example above there are two listeners activated; one is listening onport 5985 over HTTP and the other is listening on port 5986 over HTTPS. Some ofthe key options that are useful to understand are:

  • Transport: Whether the listener is run over HTTP or HTTPS, it isrecommended to use a listener over HTTPS as the data is encrypted withoutany further changes required.

  • Port: The port the listener runs on, by default it is 5985 for HTTPand 5986 for HTTPS. This port can be changed to whatever is required andcorresponds to the host var ansible_port.

  • URLPrefix: The URL prefix to listen on, by default it is wsman. Ifthis is changed, the host var ansible_winrm_path must be set to the samevalue.

  • CertificateThumbprint: If running over an HTTPS listener, this is thethumbprint of the certificate in the Windows Certificate Store that is usedin the connection. To get the details of the certificate itself, run thiscommand with the relevant certificate thumbprint in PowerShell:

  1. $thumbprint = "E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE"
  2. Get-ChildItem -Path cert:\LocalMachine\My -Recurse | Where-Object { $_.Thumbprint -eq $thumbprint } | Select-Object *

Setup WinRM Listener

There are three ways to set up a WinRM listener:

  • Using winrm quickconfig for HTTP orwinrm quickconfig -transport:https for HTTPS. This is the easiest optionto use when running outside of a domain environment and a simple listener isrequired. Unlike the other options, this process also has the added benefit ofopening up the Firewall for the ports required and starts the WinRM service.

  • Using Group Policy Objects. This is the best way to create a listener when thehost is a member of a domain because the configuration is done automaticallywithout any user input. For more information on group policy objects, see theGroup Policy Objects documentation.aspx).

  • Using PowerShell to create the listener with a specific configuration. Thiscan be done by running the following PowerShell commands:

  1. $selector_set = @{
  2. Address = "*"
  3. Transport = "HTTPS"
  4. }
  5. $value_set = @{
  6. CertificateThumbprint = "E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE"
  7. }
  8.  
  9. New-WSManInstance -ResourceURI "winrm/config/Listener" -SelectorSet $selector_set -ValueSet $value_set

To see the other options with this PowerShell cmdlet, seeNew-WSManInstance.

Note

When creating an HTTPS listener, an existing certificate needs to becreated and stored in the LocalMachine\My certificate store. Without acertificate being present in this store, most commands will fail.

Delete WinRM Listener

To remove a WinRM listener:

  1. # remove all listeners
  2. Remove-Item -Path WSMan:\localhost\Listener\* -Recurse -Force
  3.  
  4. # only remove listeners that are run over HTTPS
  5. Get-ChildItem -Path WSMan:\localhost\Listener | Where-Object { $_.Keys -contains "Transport=HTTPS" } | Remove-Item -Recurse -Force

Note

The Keys object is an array of strings, so it can contain differentvalues. 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 thefollowing command:

  1. winrm get winrm/config/Service
  2. winrm get winrm/config/Winrs

This will output something like the following:

  1. Service
  2. RootSDDL = O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;IU)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)
  3. MaxConcurrentOperations = 4294967295
  4. MaxConcurrentOperationsPerUser = 1500
  5. EnumerationTimeoutms = 240000
  6. MaxConnections = 300
  7. MaxPacketRetrievalTimeSeconds = 120
  8. AllowUnencrypted = false
  9. Auth
  10. Basic = true
  11. Kerberos = true
  12. Negotiate = true
  13. Certificate = true
  14. CredSSP = true
  15. CbtHardeningLevel = Relaxed
  16. DefaultPorts
  17. HTTP = 5985
  18. HTTPS = 5986
  19. IPv4Filter = *
  20. IPv6Filter = *
  21. EnableCompatibilityHttpListener = false
  22. EnableCompatibilityHttpsListener = false
  23. CertificateThumbprint
  24. AllowRemoteAccess = true
  25.  
  26. Winrs
  27. AllowRemoteShellAccess = true
  28. IdleTimeout = 7200000
  29. MaxConcurrentUsers = 2147483647
  30. MaxShellRunTime = 2147483647
  31. MaxProcessesPerShell = 2147483647
  32. MaxMemoryPerShellMB = 2147483647
  33. MaxShellsPerUser = 2147483647

While many of these options should rarely be changed, a few can easily impactthe operations over WinRM and are useful to understand. Some of the importantoptions are:

  • Service\AllowUnencrypted: This option defines whether WinRM will allowtraffic that is run over HTTP without message encryption. Message levelencryption is only supported when ansible_winrm_transport is ntlm,kerberos or credssp. By default this is false and should only beset to true when debugging WinRM messages.
  • Service\Auth*: These flags define what authenticationoptions are allowed with the WinRM service. By default, Negotiate (NTLM)and Kerberos are enabled.
  • Service\Auth\CbtHardeningLevel: Specifies whether channel binding tokens arenot verified (None), verified but not required (Relaxed), or verified andrequired (Strict). CBT is only used when connecting with NTLM or Kerberosover HTTPS. The downstream libraries that Ansible currently uses only supportpassing the CBT with NTLM authentication. Using Kerberos withCbtHardeningLevel = Strict will result in a 404 error.
  • Service\CertificateThumbprint: This is the thumbprint of the certificateused to encrypt the TLS channel used with CredSSP authentication. By defaultthis is empty; a self-signed certificate is generated when the WinRM servicestarts and is used in the TLS process.
  • Winrs\MaxShellRunTime: This is the maximum time, in milliseconds, that aremote command is allowed to execute.
  • Winrs\MaxMemoryPerShellMB: This is the maximum amount of memory allocatedper shell, including the shell’s child processes.

To modify a setting under the Service key in PowerShell, the followingcommand can be used:

  1. # substitute {path} with the path to the option after winrm/config/Service
  2. Set-Item -Path WSMan:\localhost\Service\{path} -Value "value here"
  3.  
  4. # for example, to change Service\Auth\CbtHardeningLevel run
  5. Set-Item -Path WSMan:\localhost\Service\Auth\CbtHardeningLevel -Value Strict

To modify a setting under the Winrs key in PowerShell, the followingcommand can be used:

  1. # substitute {path} with the path to the option after winrm/config/Winrs
  2. Set-Item -Path WSMan:\localhost\Shell\{path} -Value "value here"
  3.  
  4. # for example, to change Winrs\MaxShellRunTime run
  5. Set-Item -Path WSMan:\localhost\Shell\MaxShellRunTime -Value 2147483647

Note

If running in a domain environment, some of these options are set byGPO and cannot be changed on the host itself. When a key has beenconfigured 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 difficultto setup and configure. Because of this complexity, issues that are shown by Ansiblecould in fact be issues with the host setup instead.

One easy way to determine whether a problem is a host issue is torun the following command from another Windows host to connect to thetarget Windows host:

  1. # test out HTTP
  2. winrs -r:http://server:5985/wsman -u:Username -p:Password ipconfig
  3.  
  4. # test out HTTPS (will fail if the cert is not verifiable)
  5. winrs -r:http://server:5985/wsman -u:Username -p:Password -ssl ipconfig
  6.  
  7. # test out HTTPS, ignoring certificate verification
  8. $username = "Username"
  9. $password = ConvertTo-SecureString -String "Password" -AsPlainText -Force
  10. $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $password
  11.  
  12. $session_option = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
  13. Invoke-Command -ComputerName server -UseSSL -ScriptBlock { ipconfig } -Credential $cred -SessionOption $session_option

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 initialconnection. Some things to check for this are:

  • Verify that the credentials are correct and set properly in your inventory withansible_user and ansible_password
  • Ensure that the user is a member of the local Administrators group or has been explicitlygranted access (a connection test with the winrs command can be used torule this out).
  • Make sure that the authentication option set by ansible_winrm_transport is enabled underService\Auth*
  • If running over HTTP and not HTTPS, use ntlm, kerberos or credsspwith ansible_winrm_message_encryption: auto to enable message encryption.If using another authentication option or if the installed pywinrm version cannot beupgraded, the Service\AllowUnencrypted can be set to true but this isonly recommended for troubleshooting
  • Ensure the downstream packages pywinrm, requests-ntlm,requests-kerberos, and/or requests-credssp are up to date using pip.
  • If using Kerberos authentication, ensure that Service\Auth\CbtHardeningLevel isnot set to Strict.
  • When using Basic or Certificate authentication, make sure that the user is a local account andnot a domain account. Domain accounts do not work with Basic and Certificateauthentication.

HTTP 500 Error

These indicate an error has occured with the WinRM service. Some thingsto check for include:

  • Verify that the number of current open shells has not exceeded eitherWinRsMaxShellsPerUser or any of the other Winrs quotas haven’t beenexceeded.

Timeout Errors

These usually indicate an error with the network connection whereAnsible 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 forautomatic start

Connection Refused Errors

These usually indicate an error when trying to communicate with theWinRM service on the host. Some things to check for:

  • Ensure that the WinRM service is up and running on the host. Use(Get-Service -Name winrm).Status to get the status of the service.
  • Check that the host firewall is allowing traffic over the WinRM port. By defaultthis is 5985 for HTTP and 5986 for HTTPS.

Sometimes an installer may restart the WinRM or HTTP service and cause this error. Thebest way to deal with this is to use win_psexec from anotherWindows host.

See also