Using Linked Clones outside your View Fish Tank


Last week I had a conversation with one of my customers who asked me if I know some good, fast, modular way for provisioning around 20-25 VMs for a lab environment.

The first thing I asked was “what are you using today?” So he opened his vSphere Client and showed me how he is using NetApp Rapid Clone Utility (RCU) to deploy the VMs.

The problem with the RCU is that it isn’t elastic and modular enough although using it is great for gaining fast provisioning. You can watch a few YouTube videos here.

I’ve decided to write a PowerCLI deployment script which uses VMware’s own Linked Clone mechanism. Although it’s extensively used in View deployments, there is no reason not to use it in an old fashion deployments.

On top of the Linked Clone capabilities, the VMs are deployed using CSV parameters. That way we don’t just gain a fast deployment but also a modular scripting environment.

Now, your Linked Clones are no longer fish out of water Smile

The CSV will look like this, of course you can change it according to your environment:


The script uses Quest ActiveRoles Management Shell for Active Directory which can be downloaded from here 

[sourcecode language=”powershell”]

# Name: Linked Clone Mass Deployment.ps1
# Purpose: Automate Linked Clone deployment process.
# Created: 06/06/2013
# Author: Lior Kamrat
# Created For:
# Version: 1.0

# Import environment parameters (vCenter, CSV, Domain Credentials, Domain Name)
# Connect to vCenter server
# Load VMware $ Quest PowerShell Snapins
# Load both 64 and 32 bit Snapins

$vCenter = Read-Host "Enter vCenter Server Hostname or IP"
$CSV_Path = "CSV File Location"
Write-Host "Enter Domain Admin Credentail"
$Domain = "Domain Name"
$Domain_Credentials = Get-Credential

Connect-VIServer -Server $vCenter
if (-not (Get-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue)) {
Add-PSSnapin VMware.VimAutomation.Core
if (-not (Get-PSSnapin Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue)) {
Add-PSSnapin Quest.ActiveRoles.ADManagement
Function Get-AllPSSnapin {
$64bitsnapins = Get-PSSnapin -Registered
$32bitsnapins = & "$env:Windir\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -command {Get-PSSnapin -Registered}
$64bitsnapins + $32bitsnapins

# Import CSV file containing the VMs deployment parameters
# Map Deployment Parameters

$VMDeploymentList = Import-CSV $CSV_Path

ForEach ($vm in $VMDeploymentList) {
$VMName = $vm.Name
$Template = $vm.Template
$NumCpu = $vm.NumCpu
$MemoryMB = $vm.MemoryMB
$Customization = $vm.Customization
$Cluster = $vm.Cluster
$Folder_Location = $vm.Folder_Location
$VM_Folder = $vm.VM_Folder
$Datastore = $vm.Datastore
$IPAddress = $vm.IPAddress
$SubnetMask = $vm.SubnetMask
$PrimaryDNS = $vm.PrimaryDNS
$SecondaryDNS = $vm.SecondaryDNS
$DefaultGateway = $vm.DefaultGateway
$Notes = $vm.Notes
$ADDescription = $vm.ADDescription
$SleepInterval = 15
$ParentOU = $vm.ParentOU
$DeploymentOU = $vm.DeploymentOU

# Check if the deployment target VM folder exist in vCenter, create it if not
# Connect to a domain
# Check if the deployment target OU exist in it’s parent OU, create it if not
# Check if computer account object based on virtual machine name exist in the deployment OU, create it if not

if(-not(Get-Folder -Location $Folder_Location -Type ‘VM’ -Name $VM_Folder ))
New-Folder -Location $Folder_Location -Name $VM_Folder
Connect-QADService -Service $Domain -Credential $Domain_Credentials

if(-not(Get-QADObject -Type ‘organizationalUnit’ -Name $DeploymentOU ))
New-QADObject -ParentContainer $ParentOU -Type ‘organizationalUnit’ -NamingProperty ‘ou’ -Name $DeploymentOU
if(-not(Get-QADObject -Type ‘computer’ -Name $VMName ))
New-QADComputer -Name $VMName -SAMAccountName $VMName -ParentContainer $DeploymentOU -Description $ADDescription

# Mapping base template current snapshot variables (Parent snapshot for Linked Clones deployment)
# Deploy Linked Clone based on snapshot variables (Parent snapshot folder, clone name, clone specs)
# Wait for few seconds (determined by the SleepInterval parameter) until the clone process finish before starting customizing the Linked Clone

$SourceTemplate = Get-Template $Template | Get-View
$cloneSpec = New-Object Vmware.Vim.VirtualMachineCloneSpec
$cloneSpec.Snapshot = $SourceTemplate.Snapshot.CurrentSnapshot
$cloneFolder = $SourceTemplate.Parent
$cloneSpec.Location = New-Object Vmware.Vim.VirtualMachineRelocateSpec
$cloneSpec.Location.DiskMoveType = [Vmware.Vim.VirtualMachineRelocateDiskMoveOptions]::createNewChildDiskBacking
$SourceTemplate.CloneVM_Task( $cloneFolder, $VMName, $cloneSpec )
Start-Sleep -Seconds $SleepInterval

# Modifying the customization file with the network variables specified in the CSV file
# Change VM settings according to CSV file variables
# Power-on new created Linked Clone VM

Get-OSCustomizationSpec $Customization | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $IPAddress -SubnetMask $Subnetmask -DNS $PrimaryDNS,$SecondaryDNS -DefaultGateway $DefaultGateway
Set-VM $VMName -OSCustomizationSpec $Customization -MemoryMB $MemoryMB -NumCpu $NumCpu -Notes $Notes -Confirm:$false
Get-VM $VMName | Move-VM -Destination $VM_Folder -RunAsync:$true
Start-VM $VMName -Confirm:$false
# svMotion each Linked Clones to its dedicated datastore

ForEach ($vm in $VMDeploymentList) {
$VMName = $vm.Name
$VM_Folder = $vm.VM_Folder
$Datastore = $vm.Datastore
Get-Folder $VM_Folder | Get-VM $VMName | Move-VM -Datastore $Datastore -RunAsync:$true

#Disconnecting from vCenter

Disconnect-VIServer -Server $vCenter -Confirm:$false


  1. working with link clones trough API has some limit like number of hosts that can be access same Datastore and also that link clone between several data stores (meaning base in on one datastore and links clone are on other datastore).
    it is worth reviewing SDK.

  2. Is there any way to update the snapshot (a.k.a recompose) the existing clones without having to destroy and re-create them?

  3. Greetings Lior,

    I just started looking at the method this afternoon to deploy and was in the process of putting a script together just like this (Okay to be my wouldn’t be near as good as yours) for training VMs that grew from a base image of 15 GB to over 120 GB. and I just don’t have 2 TB for a bunch of training VMs. Great Job. Going to put the script in the LAB environment and give it a try.



  4. Greetings Lior,

    Thank you for sharing your Link Cloning script, I am very envious of your ability to create such complex scripts from scratch.

    I am curious if this script can be used to create linked clones from a snapshot or does it require a template VM?

    As you probably know too well most of us have mickey mouse ESX hosts for our home labs and it can be very slow to deploy say 10 VMs everytime. So what would be nice is to do something similar to VMware View 3Rs (as per Jeff’s question a.k.a Recompose, Refresh and Rebalance) but for ordinary VMs so as to at least keep the OS updates current without needing to individually keep updating individual VMs with MS updates etc.


Leave a Reply