Create automation ready Windows VM with Packer and Ansible.

logo for ansible vmware

Create automation ready Windows VM with Packer and Ansible.

In my environment I am using the Ansible vmware_guest module to deploy Windows Server VM’s on a vSphere platform. After using the module I should have a vm with a clean Windows Server installation which is automation ready. This works, however, the template was pretty static and kind of hard to maintain. Some necessary scripts actually resided inside the template together with an additional local user for automation purposes. Also, vmware-tools was installed manually into the template. Even though it worked, it didn’t feel quite right to me. The windows template should be as clean as possible and also, I want some centralized security for the added local user, preferably coming from the Ansible-Vault. So I started to look into creating an automation ready Windows VM with Packer and Ansible.


I heard a lot about Packer and its ease for creating templates, so I thought to give it a try. With success, because it actually is really easy to build a Windows Server template with packer on a vSphere environment. With Packer you can include scripts that need to run during first setup and it uses the autounattend.xml answerfile to satisfy most of your needs. Ofcourse possibilities seem endless, but in most cases it’s best to keep it as simple as possible.

Packer limitation

Packer does not have out-of-the-box password encryption. This means that the autounattend.xml holds the Windows Administrator password in plaintext. Also, when you run packer you need to specify the login for the vCenter so it can write the template to it. In my situation the vCenter login is not a problem. Packer does provide an option to obscure the password from logging and I am the only one creating Packer templates. The Windows Administrator password however is another story. The plaintext password used in the autounattend.xml will end up as local administrator in the template. That might pose a security risk.

note: it should be possible to secure passwords with the HashiCorp vault. In my use-case i do not have the option for this though.

Packer usage:

I am going to be a little short on this one. There are tons of good blogs and how-to’s on this. I found a nice blog and some good examples on Github. With some modifications I got this to work for me.


So, after creating my template with Packer I was satisfied on the scripting part. Every template I now create receives the same scripts in the same repeatable way. Updates and/or additions to the scripts are done through Packer. No messing around in existing or manually building templates anymore. However, there is still the issue of the plaintext password and the additional user I want. Let’s resolve this with Ansible.

Ansible vmware_guest module

I had been thinking a while on how to securely set the local administrator password and add a new local user as well. After a while I realized the answer was staring me in the face all along! Why not use the vmware-guest module and utilize the windows runonce attribute in the customization options? This attribute gives you the opportunity to execute commands from the windows command line at first logon. This means that it is possible to change the Administrator password to a vault password and that I can add a new local user also with a vault encrypted password. Very straightforward, quite easy! Ofcourse you do need an Ansible-Vault to be present to do this. For now I am going to assume you know about Ansible-Vault, if not or if you are having troubles please feel free to contact me. ( )

Flow of events

In the end of the day I want to deliver a clean and secure Windows VM with Packer and Ansible ready for receiving automation. To accomplish this I will do the following

  • create template with Packer
    • insert a dummy password for the Windows Administrator in the autounattend.xml
    • add WinRM enable script, I did modify this to enable CredSSP as well
    • install vm-tools script
    • enable-rdp script
  • set ansible vault and include the passwords for Local Administrator and the new automation user (au_user)
  • create playbook (or role) in Ansible with vmware-guest module
  • in the module utilize the customization option with runonce attribute:
    • net user /add au_user “{{ vault_au_user_password }}”
    • net localgroup administrators au_user /add
    • net user administrator “{{ vault_win_local_admin_password }}
  • make sure the module waits until customization is finished
vmware_guest module – example
- name: "deploy windows server ready for automation"
    hostname: "{{ your_vcenter_hostname }}"
    username: "{{ your_vcenter_username }}"
    password: "{{ your_vcenter_password }}"
    validate_certs: false
    datacenter: "{{ your_data_center }}"
    cluster: "{{ your_cluster_name }}"
    folder: "{{ your_folder_name }}"
    annotation: windows server created by Ansible
    use_instance_uuid: true
    guest_id: windows9Server64Guest
    datastore: "{{ your_data_store_name }}"
    template: "{{ your_packer_template }}"
      hostname: "{{ your_windows_hostname }}"
      timezone: 110
        - net user /add au_user "{{ vault_au_user_password }}"
        - net localgroup administrators au_user /add
        - net user administrator /active:no
        - net user administrator "{{ vault_win_local_admin_password }}"
      num_cpus: 1
      memory_mb: 2048
    name: "{{ your_windows_hostname }}"
      - name: "{{ your_portgroup_name }}"
        state: present
        start_connected: true
    state: present
    wait_for_customization: true
    wait_for_ip_address: true

Most of the code speaks for itself, however let me point out some critical lines.
19 adds the ‘au_user’ and uses a password that is in the vault. The vault needs to be available and encrypted ofcourse !
20 adds the ‘au_user’ to the administrators group.
21 disables the standard Local Administrator.
22 sets the password from the vault for the Local Administrator.
32 makes sure the module waits till customization is finished.

The setting in line 22 is necessary because else the Local Administrator would still hold the dummy password from the unattend.xml. This would pose a security risk because any user with sufficient rights could enable the Local Administrator user and use the dummy password for login.


It takes a little effort to figure out how to create your ‘perfect’ template with Packer. Once satisfied with requirements met you will have a very stable template though. Working from that base it is very easy to do updates and create new versions of the template based on your ‘perfect’ template.

When you combine the Packer template with the Ansible vmware_guest module for deployment and Ansible Vault for security it delivers a strong, secure and straightforward Windows VM. With CredSSP enabled for the ‘au_user’ this basic VM is ready to receive further automation and customization.

Closing Note

For the sake of the length of this blog I have chosen to skip over some items fairly easy, like setting up Packer or the Ansible Vault. Hopefully the links will provide you with enough information to set it up. If not, feel free to let me know where you get stuck and maybe I can help.

Thanks for reading !

Notify of

Inline Feedbacks
View all comments