Working with Customization Specifications in PowerCLI

This article is based on the originals that can be found here: http://blogs.vmware.com/PowerCLI/2014/05/working-customization-specifications-powercli-part-1.html

PowerCLI has several cmdlets at your disposal for managing OS Customization Specifications. In this post you will learn in more detail how to use them. In future posts we will discuss managing network interface card (NIC) mappings, cloning customization specifications and customizing VMs.

Managing customization specifications

Creating a new OSCustomizationSpec is done through New-OSCustomizationSpec cmdlet. You can create customization specifications for either Windows or Linux Virtual Machines. You specify the OS Type through the “-OSType” parameter of the cmdlet – the accepted values are “Windows” and “Linux” respectively.

When creating a Windows customization specification there are several mandatory parameters that you need to specify. These are: “Name”, “Domain” or “Workgroup”, “FullName” and “OrgName”.

Here is an example:

New-OSCustomizationSpec –Name “BasicWindowsSpec” –FullName “administrator” –OrgName “Organization” –Domain “vmware.com” –DomainUsername “user” –DomainPassword “pass” –OSType Windows

# Or, using Workgroup:

New-OSCustomizationSpec –Name “BasicWindowsSpec” –FullName “administrator” –OrgName “Organization” –Workgroup “MyWorkgroup” –OSType Windows

When creating a Linux customization specification the mandatory parameters are just “Name” and “Domain”:

New-OSCustomizationSpec –Name “BasicLinuxSpec” –Domain “vmware.com”–OSType Linux

Specifically for Linux customization specifications you can specify DnsServer parameter. The parameter accepts array of strings and the DNS servers you specify there are applicable to all network adapters of the VM. If you specify more than one value – the first one will become the primary DNS server, the second one – the secondary, and so on:

New-OSCustomizationSpec –Name “BasicLinuxSpec” –Domain “vmware.com”–OSType Linux –DnsServer “192.168.0.10”, ”192.168.0.20”

# In this case 192.168.0.10 will become the primary DNS and 192.168.0.20 – the secondary

In contrast – for Windows customization specifications you configure the DNS servers per network adapter. We will have a look at that later on.

Apart from the mandatory parameters you can also specify a variety of other settings. You can find all parameters with information about each of them in PowerCLI cmdlet reference.

The above examples create new customization specifications with the given names and save them on the server. Such specifications are referred to as “Persistent”. Once you create them they are persisted on the server and you can access them at any time, even from another PowerCLI session. You also have an option to create a “NonPersistent” specification – these are not stored on the server, but they are kept in-memory in the current PowerCLI session. Once the PowerCLI session is closed – these specifications are discarded. Later on we will demonstrate what the non-persistent specifications are useful for.

To create a non-persistent specification you need to specify that in the “–Type” parameter:

New-OSCustomizationSpec –Domain “vmware.com”–OSType Linux –Type NonPersistent

When creating non-persistent specifications you do not need to specify a name for them (you can if you want to).

To retrieve the list of existing customization specifications you can use the Get-OSCustomizationSpec cmdlet. It retrieves both persistent and non-persistent specifications. You can additionally filter the specifications by Name and/or Type (e.g. persistent/non-persistent):

Get-OSCustomizationSpec

Get-OSCustomizationSpec –Name BasicWindowsSpec

Get-OSCustomizationSpec –Type Persistent

You can modify an existing customization specification (whether it is persistent or non-persistent) by using Set-OSCustomizationSpec cmdlet. This allows you to change the parameters of the specification that were configured during its creation:

Get-OSCustomizationSpec –Name BasicWindowsSpec | Set-OSCustomizationSpec –TimeZone “Central (U.S. and Canada)”

You can find all parameters of the cmdlet in PowerCLI cmdlet reference, or by typing “Get-Help Set-OSCustomizationSpec” in the PowerShell console.

Removing a customization specification is done through Remove-OSCustomizationSpec cmdlet. The cmdlet will prompt you for confirmation before removing the object. If you don’t want to be prompted (e.g. when running a script) – you can suppress the prompt with –Confirm:$false:

Remove-OSCustomizationSpec –OSCustomizationSpec BasicWindowsSpec –Confirm:$false


PowerCLI has several cmdlets at your disposal for managing OS Customization Specifications. In the previous post we showed you how to create new customization specifications, retrieve and change them, in this post we will cover a common use case, being able to work with network interface card mappings.

Managing network interface card (NIC) mappings

One of the common things to use the customization specifications for is to configure the VM’s network adapters (e.g. static IP, DHCP, etc.). The part of the customization specification that handles the network adapters is the OSCustomizationNicMapping. Each OSCustomizationSpec can have zero or more OSCustomizationNicMappings associated with it – and each of them corresponds to a network adapter of the VM. In order for a customization to succeed – you need to have as many OSCustomizationNicMappings as the number of network adapters on the VM you are customizing. You will see an example for this later on.

PowerCLI offers 4 cmdlets for managing the NIC mappings of a customization specification – these are Get-, Set-, New- and Remove-OSCustomizationNicMapping. Creating a new OSCustomizationNicMapping is done through New-OSCustomizationNicMapping cmdlet. Since the NIC mapping is part of a customization specification – when creating one you need to specify the customization specification to which you want to add the new NIC mapping. This is done through the “-OSCustomizationSpec” parameter. With a single OSCustomizationNicMapping you can configure a network adapter to either use DHCP or static IP.

Here is an example how to configure a network adapter to use DHCP. We also configure 192.168.0.10 as the primary DNS and 192.168.0.20 as the secondary. Additionally we specify that 192.168.0.30 will be the primary WINS server and 192.168.0.40 – the secondary:

New-OSCustomizationNicMapping –OSCustomizationSpec “BasicWindowsSpec” –IpMode UseDhcp –Dns “192.168.0.10”, “192.168.0.20” –Wins “192.168.0.030”, “192.168.0.40”

The following is an example of how to configure a network adapter with static IP:

New-OSCustomizationNicMapping –OSCustomizationSpec “BasicWindowsSpec” –IpMode UseStaticIP –IpAddress “192.168.0.100” –SubnetMask “255.255.252.0” –DefaultGateway “192.168.0.1” –AlternateGateway “192.168.0.2” –Dns “192.168.0.10”

There are a couple of interesting parameters in this cmdlet – Position and NetworkAdapterMac. Since there has to be one OSCustomizationNicMapping for each network adapter of the VM – we need a way to specify which OSCustomizationNicMapping applies to which network adapter. There are a couple of ways to do this mapping.

The first one is to use Position – the positions of the NIC mappings in the OSCustomizationSpec are consecutive numbers starting from 1. The NIC mapping on position 1 will be applied to the first network adapter of the VM, the one on position 2 – to the second network adapter of the VM, and so on. When using New-OSCustomizationNicMapping – if you don’t specify a position the NIC mapping will automatically go on the last position. If you do specify a position – the NIC mapping will go on that position and any other NIC mappings with positions equal or greater than the one you specified – will have their positions shifted with +1.

# Create a new NIC mapping on position 1. If the “BasicWindowsSpec” customization spec has other NIC mappings – their positions will be shifted +1

New-OSCustomizationNicMapping –OSCustomizationSpec “BasicWindowsSpec” –IpMode UseDhcp –Position 1

The second way to map a NIC mapping to a VM’s network adapter is to use NetworkAdapterMac. Simply pass the MAC address of the network adapter to the NetworkAdapterMac parameter when creating the NIC mapping. Later on when you apply the customization specification on the VM – the NIC mapping will be applied to the desired network adapter of the VM.

# Retrieve the network adapter of the VM we want to customize (assume we have a single network adapter)

$networkAdapter = Get-VM “MyVM” | Get-NetworkAdapter

New-OSCustomizationNicMapping –OSCustomizationSpec “BasicWindowsSpec”–IpMode UseDhcp –NetworkAdapterMac $networkAdapter.MacAddress

There is one more thing worth mentioning here. When creating a new OSCustomizationSpec – by default a single OSCustomizationNicMapping is crated for it. So every OSCustomizationSpec will initially have one NIC mapping. This NIC mapping is configured with –IPMode “UseDhcp”. So you need to keep that NIC mapping in mind when configuring your customization specifications. You may either want to modify it according to your needs (with Set-OSCustomizationNicMapping – see more details below) and then add additional NIC mappings or first remove it (with Remove-OSCustomizationNicMapping) and then add the desired NIC mappings.

To retrieve the NIC mappings of an OSCustomizationSpec you can use the Get-OSCustomizationNicMapping cmdlet. This will give you information about the currently configured NIC mappings of the customization specification.

Get-OSCustomizationSpec –Name BasicWindowsSpec | Get-OSCustomizationNicMapping

You can use the output from Get-OSCustomizationNicMapping to modify or remove NIC mappings from the customization specification. Modifying them is done through Set-OSCustomizationNicMapping – this cmdlet allows you to change all properties of the NIC mapping. This is particularly useful when setting static IPs to your VMs – you can change the IP address of the NIC mapping before applying the customization specification to each VM:

$nicMapping = Get-OSCustomizationNicMapping –OSCustomizationSpec BasicWindowsSpec | where {$_.Position –eq 1}

$nicMapping | Set-OSCustomizationNicMapping –IpMode UseStaticIP –IpAddress “192.168.0.101” –SubnetMask “255.255.252.0” –DefaultGateway “192.168.0.1” –Dns “192.168.0.10”

Removing a NIC mapping is done through Remove-OSCustomizationNicMapping cmdlet:

Get-OSCustomizationNicMapping –OSCustomizationSpec BasicWindowsSpec | where {$_.Position –eq 2} | Remove-OSCustomizationNicMapping

# You can also remove all NIC mappings from the specification

$nicMappings = Get-OSCustomizationNicMapping –OSCustomizationSpec BasicWindowsSpec

Remove-OSCustomizationNicMapping –OSCustomizationNicMapping $nicMappings


PowerCLI has several cmdlets at your disposal for managing OS Customization Specifications. In our first post we showed you how to create new customization specifications, retrieve and change them, in our second post we covered a common use case, being able to work with network interface card mappings and now in this final post we will show you how to clone a customization specification and give you an end-to-end scenario showing you how to use it in a script.

Cloning customization specifications

PowerCLI also gives you the ability to clone a customization specification (which creates an identical copy). You can clone both persistent and non-persistent specifications. Cloning is useful when you want to duplicate your customization specifications across multiple vCenter Servers. Let’s say you are connected to 2 servers – “vc1” and “vc2” and you want to copy all your customization specifications from “vc1” to “vc2”. Here is how to do that:

Get-OSCustomizationSpec –Type Persistent –Server vc1 | New-OSCustomizationSpec –Server vc2 –Type Persistent

You can also clone a customization specification as a non-persistent one. This is useful when you will be applying this specification to multiple VMs and will need to change the NIC mappings for each VM. Here is how to create a non-persistent clone of a customization specification:

$clone = Get-OSCustomizationSpec –Name BasicWindowsSpec | New-OSCustomizationSpec –Type NonPersistent

Customizing VMs

Now let’s see an end-to-end scenario. You need to deploy 100 new Linux VMs (with a single network adapter) and configure them to use static IPs. You have a list of static IPs in a CSV file.

# We will name the VMs “VM-001”, “VM-002” … “VM-100”

$vmNameTemplate = “VM-{0:D3}”

# The VMs will be created in “MyCluster” and will be based on “Rhel6_VM” template

$cluster = Get-Cluster MyCluster

$template = Get-Template Rhel6_VM

# Create the VMs

$vmList = @()

for ($i = 1; $i –le 100; $i++) {

$vmName = $vmNameTemplate –f $i

$vmList += New-VM –Name $vmName –ResourcePool $cluster –Template $template

}

# The list of static IPs is stored in “StaticIPs.csv” file

$staticIpList = Import-CSV C:\StaticIPs.csv

# Create the customization specification

$linuxSpec = New-OSCustomizationSpec –Name LinuxCustomization –Domain vmware.com –DnsServer “192.168.0.10”, “192.168.0.20” –NamingScheme VM –OSType Linux

# We will be applying this specification to each of our 100 VMs.

# However each time before applying it we need to change the static IP in the NIC mapping.

# Instead of changing the specification that is persisted on the server (and can be reused in the future)

# we will clone it to a non-persistent one and change that instead:

$specClone = New-OSCustomizationSpec –Spec $linuxSpec –Type NonPersistent

# Now apply the customization specification to each VM

for ($i = 0; $i –lt $vmList.Count; $i++) {

# Acquire a new static IP from the list

$ip = $staticIpList[$i].IP

# The specification has a default NIC mapping – retrieve it and update it with the static IP

$nicMapping = Get-OSCustomizationNicMapping –OSCustomizationSpec $specClone

$nicMapping | Set-OSCustomizationNicMapping –IpMode UseStaticIP –IpAddress $ip –SubnetMask “255.255.252.0” –DefaultGateway “192.168.0.1”

# Apply the customization

Set-VM –VM $vmList[$i] –OSCustomizationSpec $specClone –Confirm:$false

}

What if our VMs have more than one network adapter? For simplicity let’s assume that our VMs are already created (and stored in $vmList variable) and each of them has two network adapters – one of them attached to “Public” network and the other to “Private” network. We need to configure the network adapters on the “Public” network with static IPs and the ones on “Private” network to use DHCP.

# The list of static IPs is stored in “StaticIPs.csv” file

$staticIpList = Import-CSV C:\StaticIPs.csv

# Create the customization specification . This time we will directly create a non-persistent specification, so we don’t need to specify a name for it

$linuxSpec = New-OSCustomizationSpec –Domain vmware.com –DnsServer “192.168.0.10”, “192.168.0.20” –NamingScheme VM –OSType Linux –Type NonPersistent

# Now apply the customization specification to each VM

for ($i = 0; $i –lt $vmList.Count; $i++) {

# Acquire a new static IP from the list

$ip = $staticIpList[$i].IP

# Remove any NIC mappings from the specification

$nicMapping = Get-OSCustomizationNicMapping –OSCustomizationSpec $linuxSpec

Remove-OSCustomizationNicMapping –OSCustomizationNicMapping $nicMapping –Confirm:$false

# Retrieve the VM’s network adapter on the “Public” network

$publicNIC = $vmList[$i] | Get-NetworkAdapter | where {$_.NetworkName -eq “Public”}

# Retrieve the VM’s network adapter on the “Private” network

$privateNIC = $vmList[$i] | Get-NetworkAdapter | where {$_.NetworkName -eq “Private”}

# Create a NIC mapping for the “Public” NIC – it will use static IP

$linuxSpec | New-OSCustomizationNicMapping –IpMode UseStaticIP –IpAddress $ip –SubnetMask “255.255.252.0” –DefaultGateway “192.168.0.1” –NetworkAdapterMac $publicNIC.MacAddress

# Create a NIC mapping for the “Private” NIC – it will use DHCP and we will map it by MAC address

$linuxSpec | New-OSCustomizationNicMapping –IpMode UseDhcp –NetworkAdapterMac $privateNIC.MacAddress

# Apply the customization

Set-VM –VM $vmList[$i] –OSCustomizationSpec $linuxSpec –Confirm:$false

}