Customization

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.

Comments

8 comments have been added so far

    1. 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.

  1. 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?

  2. 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.

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

  4. 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.

  5. I’m on the fence about this, while more customization is good, I have a feeling this is a “in-progress” update, it just feels incomplete and half-way there.
    We use badge layout for apps on design approvals (visual projects), so the image being displayed is important. Old layout “feels like” it had larger images,
    maybe because the images were cropped more loosely so it’s easier to tell which project it was at quick glance. Now the image is cropped closer, making it
    harder to scan thru at quick glance. I find myself needing to click into the project more often than usual. Which makes the whole user experience less
    efficient.
    I have a couple suggestions that might make it work better:
    1. Increase the height of the window the cover image is being displayed.
    2. Let us to choose which image to be displayed as “cover” (like how Pinterest handles cover images of each board, was hoping for this for a long time)
    3. Let us adjust which part of the image to show and how tight or loose the crop is (with a fixed window, let us move the image around and maybe enlarge or
    shrink it to control what shows thru the window. Pinterest does a limited form of this, which is very useful in making the cover image relevant)
    4. Allow Cover Image to be ordered in different hierarchy (currently every element can be ordered differently except the Cover Image, it seems to be stuck
    in the 2nd spot, would like the option to set it on another spot in the layout. This one seems like an easy fix, since you guys allow that for every other
    element already)

Leave a Reply

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