9 min read

‘No Windows, No Problem … What?’ | Altenar Explores How Ansible Allows Users To Manage Windows Infrastructure

 ‘No Windows, No Problem … What?’ | Altenar Explores How Ansible Allows Users To Manage Windows Infrastructure 

Altenar, a sportsbook software provider, details in the below article, its experience with Ansible, Windows and modern stacks, to illuminate the insights it’s learned over the years that could be beneficial, if not utterly intriguing, to you. 

Altenar, a sportsbook software provider, aims to create usable, informative and interactive content that can help bring the technically minded closer together. 

As a prelude to this article, an Altenar spokesperson notes, “although we have been running a modern stack (k8s, helm, .net core, etc) in production for about four years, that’s not how it has always been. Our first version of Sportsbook was Windows-based (.NET + MSSQL), and we managed 100+ servers via Ansible.”

Adding, “No Windows, no problems.” - that is the answer I got by asking a guru of Ansible "How do you manage Windows?" on one of the local Ansible meetups.”

Continue reading ‘No Windows, No Problem … what?!’ to discover more from a sports betting industry leader… 

Prepare Your Servers for Ansible

Unlike Linux, Windows requires you to prepare for Ansible to connect to it (more details available here and all the details are out of the scope of this article). However, there is one key point to stress here. The ConfigureRemotingForAnsible.ps1 script - that is pretty much what you need to run before you'll be able to connect to a VM via Ansible.

It's worth mentioning that we, Altenar,  use Terraform for VM provisioning and this is where run_once_command_list becomes very handy. We saved ConfigureRemotingForAnsible.ps1 on the C:/ of the base VM template and used the following option in Terraform: 

resource "vsphere_virtual_machine" "vm" {

  # ... other configuration ...

  clone {

    # ... other configuration ...

    customize {

      # ... other configuration ...

      windows_options {

        computer_name         = "${lower(var.envname)}${var.vmname}${format("%03d", count.index)}"

        organization_name     = "Altenar"

        join_domain           = "${var.domain}"

        domain_admin_user     = "${var.domain_user}"

        domain_admin_password = "${var.domain_password}"

        admin_password        = "${var.admin_password}"

        auto_logon            = true

        run_once_command_list = [

            "powershell.exe -version 4 -ExecutionPolicy Bypass -File C:\\ConfigureRemotingForAnsible.ps1",






Once a new server is provisioned it is ready to be set up by Ansible according to the role we assign to the server.

How To Set Up Ansible

From the Ansible side, a few initial preparations are also required.

Step One: Make sure all Windows servers belong to the "Windows" group in your inventory, we use groups but you can list each server individually here or automate the inventory creation process. Inventory management is out of this article scope, but it is well described in Ansible documentation:






Step Two: Create windows.yaml file in group_vars folder of each environment and/or in the main group_vars folder and add the following content:



ansible_user: "{{ windows_user|default ('Administrator') }}"

ansible_password: "{{ windows_password }}"

ansible_port: 5986

ansible_connection: winrm

ansible_winrm_transport: credssp


Step Three: Include this role as dependent into the meta/main.yaml file of any of the roles you are planning to execute, for instance:

# cat roles/infra/IIS/meta/main.yml



  - { role: infra/fetch-credentials/windows }

This role checks appropriate environment variables and fails if a Username or Password is not provided. These environment variables are then copied to Ansible variables and used in the settings we defined in p2. 

Step Four: At this time, we have our servers configured and Ansible set up. We are good to go, the only thing left is actually setting up Windows username and password.

You can achieve this through one of two ways. 

1st Way: You can do it using export WINDOWS_USERNAMEand export WINDOWS_PASSWORD commands:

export WINDOWS_USERNAME=Administrator

export WINDOWS_PASSWORD=******

2nd Way: or if you have more than one set of credentials you can use a small bash script-helper:

# source

Set Value for WINDOWS_DOMAIN_USER: Administrator


Set Value for WINDOWS_USER: Administrator


Our preparations are done. We are ready to start Ansibling.

Windows tips and tricks

Ansible has much fewer modules for Windows than for Linux. There are 104 modules for windows out of 2832 in total yet it is enough for most of the common cases. But sometimes we have to be creative.

DSL is your friend

The first thing to remember - DSL is your friend. There are many DSL modules for windows, for example using this module you can install MSSQL by just one task:

- name: Configure SqlSetup


    resource_name: SqlSetup

    ForceReboot: False

    UpdateEnabled: False

    SourcePath: "{{ disk_image_out.mount_path|default(database_settings.mssql_installation_source) }}"

    InstanceName: "{{ db_settings.instance_name|upper }}"

    Features: "{{ sql_setup_components }}"

    InstallSharedDir: "{{ db_settings.instance_dir_drive }}Program Files\\Microsoft SQL Server"

    InstallSharedWOWDir: "{{ db_settings.instance_dir_drive }}Program Files (x86)\\Microsoft SQL Server"

    InstanceDir: "{{ db_settings.instance_dir_drive }}SQL"

    SQLCollation: 'Latin1_General_CI_AS'

    SQLSvcAccount_username: "{{ ad_settings_domain }}\\{{ db_settings.sqlsvcaccount }}$"

    SQLSvcAccount_password: '***'

    AgtSvcAccount_username: "{{ ad_settings_domain }}\\{{ db_settings.agtsvcaccount }}$"

    AgtSvcAccount_password: '***'

    SQLSysAdminAccounts: "{{ ad_settings_domain|upper }}\\SQL Administrators"

    InstallSQLDataDir:  "{{db_settings.data_dir_drive}}SQL\\{{ db_settings.instance_name|upper }}\\MSSQL\\Data"

    SQLUserDBDir:       "{{db_settings.data_dir_drive}}SQL\\{{ db_settings.instance_name|upper }}\\MSSQL\\Data"

    SQLUserDBLogDir:    "{{db_settings.log_dir_drive }}SQL\\{{ db_settings.instance_name|upper }}\\MSSQL\\Log"

    SQLTempDBDir:       "{{db_settings.temp_dir_drive}}SQL\\{{ db_settings.instance_name|upper }}\\MSSQL\\Data\\Tempdb"

    SQLTempDBLogDir:    "{{db_settings.temp_dir_drive}}SQL\\{{ db_settings.instance_name|upper }}\\MSSQL\\Log\\Tempdb"

    SQLBackupDir:       "{{db_settings.backup_dir_drive}}SQL\\{{ db_settings.instance_name|upper }}\\MSSQL\\Backup"

    PsDscRunAsCredential_username: "{{ad_settings_adminuser}}@{{ad_settings_domain}}"

    PsDscRunAsCredential_password: "{{ad_settings_adminpassword}}"


  - install_db

Use the win_psmodule first to install the required DSC modules on the server first:

- name: install DSC Modules


    name: "{{ item }}"

    state: present


    - "PSDesiredStateConfiguration"

    - "SqlServerDsc"

    - "ServerManager"

    - "StorageDsc"

    - "ComputerManagementDsc"

Another big advantage of DSC is that you can run it as a different user, you could've spotted "PsDscRunAsCredential_username" and "PsDscRunAsCredential_password" directives in the example above. It especially helps when some tasks have to be run from the Domain Administrator account.

DIY modules

Didn't find an appropriate DSC module? Not a big deal, there are two possible workarounds (apart from the obvious - using win_shell ansible module):

Step One: Use DSC resource "Script":

#Part of MSSQL setup playbook. Here we test if created service accounts 

#have already been added to the server from AD

#if not, we reboot the servers first.

- name: Configure and Test the gMSA account


    resource_name: Script

    GetScript: "@{ Result = '{{ item }}'| Use-ServiceAccount -Test }"

    TestScript: "(iwr -UseBasicParsing).Content | iex; '{{ item }}'| Use-ServiceAccount -Test"

    SetScript: '$global:DSCMachineStatus = 1'

    PsDscRunAsCredential_username: "{{ad_settings_adminuser}}@{{ad_settings_domain}}"

    PsDscRunAsCredential_password: "{{ad_settings_adminpassword}}"


    - "{{ db_settings.sqlsvcaccount }}"

    - "{{ db_settings.agtsvcaccount }}"

register: TestADServiceAccount_result

Step Two: Ansible is an imperative tool, so we have to make sure that any task can be executed multiple times providing us with the same result. Play with "GetScrypt", "TestScrypt" and "SetScrypt" fields according to your needs. Having it played right should allow you to be able to identify the current state of the resource, change it if required and pass if not.

Step Three: Create a module yourself. It's not that hard, the only difference with making a module for Linux is you need to write code on PowerShell. We encountered a problem where there was no module KDS Root Key creation which is required for MSSQL installation. So we created it. Look here for more details regarding win module development.


Providing the key aspects related to Ansible usage with Windows. Having Windows servers configured for Ansible we can manage them nearly the same way as we manage Linux servers using Ansible. By using the approaches described in this article we successfully manage Windows servers for jobs like:

  • MSSQL AG cluster installation and update.
  • IIS configuration.
  • Windows services failover cluster configuration.
  • A/B deployment.

Discover more about Altenar and harness its growing and expanding expertise by contacting the award-winning team today!


This site uses cookies to offer you a better browsing experience. Find out more on how we use cookies and how you can change your settings.