Home > Blogs > VMware PowerCLI Blog


Working with Customization Specifications in PowerCLI Part 3

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

}

clip_image002[8]This post was created by Dimitar Barfonchovski.

Dimitar joined VMware and the PowerCLI team in 2007. He is member of the development part of the team and his main responsibilities are the functional design and implementation of features for the vSphere and vCloud PowerCLI components.

As with all members of the team, he is working to deliver a good and valuable product. He is also working to improve all processes and tools involved in the product development and validation.

This entry was posted in Customization and tagged on by .
Alan Renouf

About Alan Renouf

Alan Renouf is a Product Line Manager at VMware focusing on API's, SDK's and CLI's, He is responsible for providing the architects and operators of private and public cloud infrastructure with the toolkits/frameworks and command-line interfaces they require to build a fully automated software-defined datacenter. Alan is a frequent blogger at http://blogs.vmware.com/PowerCLI a book author and has a personal blog at http://virtu-al.net. You can follow Alan on twitter as @alanrenouf.

7 thoughts on “Working with Customization Specifications in PowerCLI Part 3

  1. Shawn

    Any reason why Set-OSCustomizationNicMapping is not able to set the DNS servers on a Linux spec?

    Reply
    1. Dimitar Barfonchovski

      This is because the DNS settings for Linux are global and are configured through the OSCustomizationSpec – there can’t be different DNS settings for the different network adapters (like for Windows VMs). This is a vSphere limitation.

      Reply
  2. Richard

    Does New-OSCustomizationNicMapping support IPv6 and apply an IPv6 address to a Windows Server?

    Reply
  3. Bryan

    Hello Dimitar,
    I hope you are still checking this site. Presently I having trouble with cloning new WIndows 7 VM. The new vm’s need to have their hostname’s changed and joined to a domain. They will use a DHCP address also. So far I can use PowerCLI to create the new vm but the OSCustomizationSpec is failing to rename the Windows workstation and join to the domain. I also sysprep’d with the generalize option the template but all this did was make the Out of Box Experience (OOBE) appear which required interaction.

    I am trying to create a batch of workstations from a CSV file using a template, rename them, and join them to the domain. Here is what I have right now:

    $vms = Import-CSV C:\users\bryan\desktop\New-VM.csv

    function WaitForFinish ($vmname)
    {
    do
    {
    sleep 2
    } while ((Get-VM -Name $vm.name).MemoryGB -eq 0)

    }

    $i = 0

    foreach ($vm in $vms){
    $Template = Get-Template $vm.template
    $VMHost = Get-VMHost $vm.host
    $Datastore = Get-Datastore $vm.datastore
    $OSCustomization = Get-OSCustomizationSpec $vm.customization
    write-progress -activity “Cloning VM’s” -status (“Cloning VM(” + ($i+1) + “/” + $vms.count + “): ” + $Name) -percentComplete (($i / $vms.count) * 100)
    New-VM -Name $vm.name $Template -VMHost $VMHost -Datastore $Datastore -OSCustomizationSpec $OSCustomization -RunAsync
    WaitForFinish $vm.name
    Start-VM -VM $vm.name
    Get-VM $vm.name | Get-NetworkAdapter | Set-NetworkAdapter -Connected:$true
    $i++
    }

    Any thoughts why I am having trouble?

    Reply
  4. Hahn

    Thanks for this wonderful posting!

    I did want to do the exactly same job as deploying tens of new Linux VMs (with a single network adapter) from a template and configuring them to use static IPs.

    I ended up succeeding creating the linux vms as I wanted, but failing to apply the non-persistent specifications to them.

    In retrospect, I did not install the matching vmtools (An open-vmtools was installed instead.) and Perl in the template VM.

    I believe it was the root cause for the half success.

    Reply
  5. tbrock

    This absolutely does not work for me in PowerCLI 6.5.4.
    Get-OSCustomizationSpec –Type Persistent –Server vc1 | New-OSCustomizationSpec –Server vc2 –Type Persistent

    Reply
  6. tbrock47

    This absolutely does not work for me in PowerCLI 6.5.4.
    Get-OSCustomizationSpec –Type Persistent –Server vc1 | New-OSCustomizationSpec –Server vc2 –Type Persistent

    I get this error:
    New-OSCustomizationSpec The object or item referred to could not be found.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

*