Dynamic VM Provisioning using PowerCLI and vSphere Customization Specifications

The Customization Specifications Manager in VMware vSphere provides a powerful tool for tweaking a newly minted VM. You can configure all sorts of parameters, such as the VM’s name, license information, domain, network settings, and so on. However, there are many limitations when using customization specifications in the vSphere Client, such as only being able to use it when creating a VM from scratch, and not being able to apply it to do “mass provisioning” of VMs (i.e. one at a time).

Fortunately, PowerCLI provides a great method for breathing new functionality into customization specifications to do both multi-VM provisioning and post-provisioning customization. This post will review the basic functions that you can call from PowerCLI and cover a few methods to both dynamically edit the specifications and bake them into a VM provisioning process.

Manipulating Customization Specifications from PowerCLI

To start, I recommend creating a special customization specification that will be used only with PowerCLI to avoid polluting any of your day-to-day specifications that you use by hand. I use the unimaginative name of “PowerCLI” for my specification. It also has a description of “Do not use this in the GUI – only for PowerCLI assisted scripting” to help remind people never to use this specification by hand because the specification will be dynamically altered by scripts and therefore will never be in a completely usable state for GUI deployment.

A base customization specification for PowerCLI use

Now that you have a base of operations, I suggest editing the PowerCLI customization specification and setting as many known good values as you can. This would be things like the Name and Organization used (typically something static like “IT Department” and “Company Name”), the NetBIOS name (I stick with “Use the virtual machine name”), licensing (KMS or specific VL/MAK keys), time zone, etc. These values often do not change and it’s good to go ahead and populate them. The main dynamic values are going to be: Workgroup or Domain, Network, and possibly License (when doing 2008 vs older operating systems).

You can now connect to the vCenter server using PowerCLI and gather the details of your new PowerCLI customization specification:

$cs = Get-OSCustomizationSpec PowerCLI

At this point, if you try to set the values of any of the child objects of $cs you’ll be rewarded with an error. For example, if I try to change the Domain from “wahlnetwork.com” to “wahlcorp.com” I’ll get an error stating that the property is ReadOnly.

You can’t directly change the objects with the customization specification

The proper way to set the properties of this variable are by using the Set-OSCustomizationSpec cmdlet.

The Set-OSCustomizationSpec cmdlet allows you to define properties

Configuring Network Settings in a Customization Specification

Now that you’ve seen how to manipulate the configuration of a customization specification, you also need to know how to change network settings. The easiest way to do this is to pipe the data into a Set-OSCustomizationNicMapping cmdlet. This will allow you to change the gateway, IP address, WINS, mask, and so on for a customization specification.

[symple_box color=”black” fade_in=”false” float=”center” text_align=”left” width=””]You can find all of my various PowerShell scripts in my GitHub repository[/symple_box]

Here is an example command:

Connect-VIServer -Credential (Get-Credential)
Get-OSCustomizationSpec $args[0]
` | Get-OSCustomizationNicMapping
` | Set-OSCustomizationNicMapping
` -IpMode:UseStaticIP
` -IpAddress (Read-Host "IP Address: ")
` -SubnetMask (Read-Host "Subnet Mask: ")
` -Dns (Read-Host "DNS Server IP: ")
` -DefaultGateway (Read-Host "Default Gateway IP: ")

Putting it All Together

Now that you have the tools necessary to change the settings and network configuration of a customization specification, you can create a script that dynamically changes the customization specification on the fly.

Some ideas from this point:

  1. Create Read-Host prompts to request that the user enter network configuration info (IP, mask, gateway, DNS) for a set of VMs that are either existing or being created.
  2. Ask the user for a Domain to put the VM in (for multi-domain environments) and use this for the DNS information.
  3. If you have multiple Datacenters, request the user specify one and base your customization off that (such as IP range)
  4. Use a specific folder for customizing newly minted VMs and have a script that loops through them applying a customization specification with a range of network information, such as “IP Range of through 103).

To apply a customization specification to a VM, use this command (make sure the VM is powered off).

[sourcecode language=”powershell”]Set-VM -OSCustomizationSpec PowerCLI -Name MyNewVM[/sourcecode]

Once the cmdlet finishes, power on the VM; it will take a few minutes to customize (sysprep).


The goal of this post is to give you some ideas on how versatile PowerCLI can be when making VMs in bulk. I find PowerCLI especially helpful when using a SAN based cloning technology (such as NetApp’s Rapid Clone Utility) that can provision many deduplicated VMs quickly, but is not able to handle customization specifications with user defined input (such as IP address). Customzing a VM after it has been created allows me to script through a set of IPs and quickly fire up batches of new VMs without much effort.

For further ideas, you might consider making a modular script that handles end-to-end provisioning with PowerCLI. The following are items in my provisioning PowerCLI script:

  • Creation – Template selection and VM creation (when not using NetApp Rapid Clone Utility)
  • Customization specifications – IP, DNS, Domain or Workgroup, and verify CPU/Mem
  • Enterprise Configuration – Add the VM to the correct AD OU, install applications (such as AV), configure guest settings / patches / updates
  • Annotations – Set the vCenter annotations