vRAC AWS Windows Domain Join using Ansible

My most recent vRealize Automation Cloud (vRAC) task was to leverage Ansible to join a new AWS Windows machine to an Active Directory domain.

First off I needed to figure out how to get WinRM working in an AWS AMI. Initially I just deployed a Windows instance, installed WinRM, added a new account admin account, then created a private AMI. This did work, sometimes, but really wasn’t the best solution for the customer. What I really needed was a way to install WinRM and create the new user in an EC2 instance deployed from a publicly available AMI.

The dots finally connected last week when it dawned on me that vRAC cloudConfig equals AWS instance User Data. Yes it was that simple.

After reviewing Running Commands on your Windows Instance at Launch, and some tinkering I came up with this basic vRAC cloudConfig PowerShell script. It adds the new user in the local Administrators group, then installs and configures WinRM. This leaves me a clean Ansible ready machine.

  cloudConfig: |
    # Add new user for ansible access
    $password = ConvertTo-SecureString ${input.new_user_password} -AsPlainText -Force
    $newUser = New-LocalUser -Name "${input.new_user_name}" -Password $password -FullName "Ansible Remote User" -Description "Ansible remote user" 
    Add-LocalGroupMember -Group "Administrators" -Member "${input.new_user_name}"    
    # Setup WinRM
    Invoke-Expression ((New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1'))

The resulting instance User Data includes the expanded variables as seen below.

# Add new user for ansible access
$password = ConvertTo-SecureString VMware123! -AsPlainText -Force
$newUser = New-LocalUser -Name "ansibleuser" -Password $password -FullName "Ansible Remote User" -Description "Ansible remote user" 
Add-LocalGroupMember -Group "Administrators" -Member "ansibleuser"    
# Setup WinRM
Invoke-Expression ((New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1'))

The playbook turned out to be fairly simple. It waits for 5 minutes, points DNS to the DC (also running DNS), renames the machine, and joins it to the domain.

- hosts: win
  gather_facts: no

  - name: Pause for OS
      minutes: 5

  - name: Change DNS to DC
      adapter_names: '*'

  - name: Rename machine
      name: "{{ hostname }}"
    register: res

  - name: Reboot if necessary
    when: res.reboot_required

  - name: Wait for WinRM to be reachable
      timeout: 900

  - name: Join to "{{ domain_name }}"
      hostname: "{{ hostname }}"
      dns_domain_name: "{{ domain_name }}"
      domain_admin_user: "{{ domain_user }}"
      domain_admin_password: "{{ domain_user_password }}"
      domain_ou_path: "{{ domain_oupath }}"
      state: domain
    register: domain_state

  - name: Wait for 2 minutes
      minutes: 2

  - name: reboot if necessary
      post_reboot_delay: 120
    when: domain_state.reboot_required

Blending existing AWS User Data with vRAC cloudConfig finally provided a clean solution without having to write a super complex ansible playbook. Keeping it simple once again pays off.

The blueprint and playbook referenced in this article are available this github repo.

vRealize Automation Cloud Ansible Enhancements

VMware released some Ansible enhancements within the last couple of weeks.

First is the ability to use the private IP of the deployed machine.  Prior the this fix, disabling the public IP threw and error and the deployment failed.

To disable the assignment of a pubic IP (default), simply add ‘assignPublicIpAddress: false‘ in the network properties.

  type: Cloud.Machine
      keyPair: id_rsa
      authentication: keyPairName
      image: CentOS 7
      flavor: generic.tiny
        - source: '${resource.Cloud_Volume_1.id}'
        - network: '${resource.Cloud_Network_1.id}'
          assignPublicIpAddress: false

By default, vRAC will use the private ip address of the first NIC on the machine.

Just a few things about the placement of the machines.  First my Ansible Control Host (ACH) is on a Public AWS subnet.  My first attempt to install NGINX on a machine deployed to the same subnet failed as it could not find the repo.  After some troubleshooting I determined the new machine needs to be deployed on a private subnet, with a NAT Gateway.  Oh and make sure the ACH can connect to the deployed machine on TCP port 22 (SSH).

The second was having the ability to send extra variables to the ACH.  Here the use case is to join an AWS backed Windows server to a domain using an ansible playbook.

Ansible extra variables can be added under the properties in the Ansible component.  Here I’m going to add several just to demonstrate what it looks like.

  type: Cloud.Ansible
    host: '${resource.Cloud_Machine_1.*}'
    osType: linux
    account: ansible-control-host
    username: centos
    privateKeyFile: /home/ansibleoss/.ssh/id_rsa
      - /home/ansibleoss/playbooks/centos-nginx/playbook.yml
      - linux
      bluePrintName: BP- ${env.blueprintName}
      message: Hello World
      domain: corp.local
      orgUnit: ou=sample,dc=corp,dc=local
          size: '${resource.Cloud_Volume_1.capacityGb}'
          label: '${input.disk1_label}'
          size: 20
          label: Fake disk

These variables are stored in /etc/ansible/host_vars/vra_user_host_vars.yml.

This is the resulting YAML file for this blueprint request.


They also changed the default connection type to winrm (default is SSH) if the osType is set to ‘windows’.

This will be the topic of my next article.

Stay tuned.

vRA Custom Forms Regex

A recent customer request was to have the linux machine names entered manually, always be in lower case, and be 13 characters long.

Initially I tinkered with a basic Event Broker Service (EBS) Subscription to simply change the ‘Hostname’ to lower case, but then decided to enforce it in a custom form.

My first task was finding the correct expression using some search sites. After a few clicks I was able to find what I was looking for.

My working expression ended up looking like this.


Click on the Hostname field on your custom form, then the Constraints tab and paste the expression in Regular expression, and provide a useful error in the Validation error message text box.


Make sure to click the form Save button before moving to another field.  I failed to do that a few times, only to discover a blank field when troubleshooting.


While the customer didn’t have a specific requirement for the other fields, I decided to research and test some other expressions for future reference. I’m sure some additional tweaking will be needed, but here goes.

IP Address / DNS Server / Gateway


Subnet Mask


Domain name


There you go. As always your mileage may vary.


vRA Custom Form CSS rendering issues

I ran into some interesting issues when trying to develop a custom form in vRealize Automation.

The first one was noticed when I tried to apply font-size to a field.  After doing some research and watching a few videos, it looked like some Field ID’s simply could not be mapped in CSS.  The main issue is the Field ID has a tilde ‘~’ in it, which is not a valid CSS ID.


A quick search resulted in an amazingly simple solution.  Escape the tilde with a backslash ‘\’.  Stupid easy!

My CSS up to this point contained the following;

body {
font-size: 18px;

#vSphere__vCenter__Machine_1\~size {
font-size: 14px; 

#integerField_cda957b7 {
font-size: 20px;
font-style: italic;

#vSphere__vCenter__Machine_1\~VirtualMachine.Disk1.Size {
font-size: 32px;

Which produced this form.


The integerField and Size (Component Profile) updated properly, but the Requested Disk Size didn’t.  (This field is actually updated using an external vRO action to change the Integer into a String, then applied to a custom property).  Ok, what I was actually after was getting rid of the Label word wrap, but stumbled across the font-size issue along the way.

After digging through some debugging info I ran into two classes, one was ‘grid-item’, and the second was ‘label.field-label.required’.


After updating CSS, I was finally able to change the Requested Disk Size font, as well as fixed the word wrap issue.

My final result is a good starting point.  Both Size and Requested Disk Size fields had a font size of 18, and the integer field had an italicized font with the correct size.  The shadow on the Size Label was just for fun 🙂


My final CSS looks like this;

body {
font-size: 18px;

.label.field-label.required {
width: 80%!important;

.grid-item {
width: 80%!important;

#vSphere__vCenter__Machine_1\~size {
/* font-size: 14px; */
color: blue;
text-shadow: 3px 2px red;
#integerField_cda957b7 {
font-size: 20px;
font-style: italic;
#vSphere__vCenter__Machine_1\~VirtualMachine.Disk1.Size {
/* does not work with custom properties */
/* need to dig into label.field.label.* */
font-size: 32px;

Well its’ about the time of day. Be well.