There are many options for cloning VMs that are not available through vSphere Client. The vSphere API CloneVM is available to users of vCenter Server and allows you to specify:

  • Whether the clone should be a fully-cloned VM or a linked clone (usually created very quickly, because it shares the disk of the source VM instead of copying it)
  • Whether to clone from a snapshot point (an earlier, saved state of the VM) or from the current state of the VM
  • Whether all the delta disks in the VM should be collapsed in into a single disk in the clone or should be copied as separate disks (if a VM has snapshots, and therefore a delta disk tree)
  • Whether the clone’s root/parent disk will be thick or thin provisioned (if creating a full clone)
  • Whether the clone should be powered on after being created
  • Whether the clone should be marked as a template
  • The folder, datastore, cluster, resource pool, and host where the clone should be created

For a non-PowerShell-based explanation, see the “Linked Virtual Machines” Technical Note from VMware.

The CloneVM API appears as a method of a VirtualMachine and takes three parameters:

$vm.CloneVM_Task( $cloneFolder, $cloneName, $cloneSpec )

Source VM, target VM name, and target folder.
In the following code, $vm should refer to a view of a VirtualMachine and $cloneName should be the name of the cloned VM that we are creating.

$vm = GetVM "<vm name>" | GetView
$cloneName = "<clone name>"

We must specify the target folder for the clone. If we want the cloned VM to appear in the same folder as an existing VirtualMachine, we only have to set $cloneFolder parameter to the ‘parent’ property of that VM. To use the same location as the source VM:

$cloneFolder = $vm.parent

All other options go inside the $cloneSpec parameter, which is of type VirtualMachineCloneSpec:

$cloneSpec = new-object Vmware.Vim.VirtualMachineCloneSpec

Target host, datastore, cluster, and resource pool.
We must create a VirtualMachineRelocateSpec object:

$cloneSpec.Location = new-object Vmware.Vim.VirtualMachineRelocateSpec  # required

Here we can optionally specify the target location for the cloned VM. We can specify the MoRef field (managed object reference) from the view object of a Datastore, Pool, and/or Host. All are optional. We can specify a cluster by specifying the name of a resource pool we have created in the cluster, or by specifying the default name for the root resource pool within a cluster, “Resources”.

$cloneSpec.Location.Pool = (getcluster "somecluster" | getresourcepool "Resources" | getview).MoRef
$cloneSpec.Location.Host = (getvm "somevm" | getvmhost | getview).MoRef
$cloneSpec.Location.Datastore = (getdatastore vm "anothervm" | getview).MoRef

Cloning from a snapshot.
Normally, when you make a clone in vSphere Client, you clone the VM in its current state. If you want to create a clone from an earlier state of a VM that has been saved to a snapshot, then vSphere Client would make you revert to that snapshot and then clone the VM. With the CloneVM API, you can directly clone from any snapshot without changing the state of the source VM. To clone from the “latest” snapshot (the parent disk of the you-are-here delta disk):

$cloneSpec.Snapshot = $vm.Snapshot.CurrentSnapshot

You can also find a snapshot by navigating the snapshot tree. This clones from the root snapshot:

$cloneSpec.Snapshot = $vm.Snapshot.RootSnapshotList[0].snapshot

If you leave the Snapshot field blank, then the clone operation will copy the current state of the VM, which is normally what you want to do when you’re creating a full clone. But if you are creating a linked clone using the DiskMoveType = “createNewChildDiskBacking” option described below, then you must specify the snapshot that you want to make a clone from (and the snapshot must exist on the VM).

Linked clones vs. Full Clones.
There are four major options to indicate the way that a VirtualMachine’s disks should be cloned.

  1. To quickly create a linked clone with a new, empty delta disk that is a child disk of the specified snapshot’s disk backing:
    $cloneSpec.Location.DiskMoveType = [Vmware.Vim.VirtualMachineRelocateDiskMoveOptions]::createNewChildDiskBacking

    This option requires that a snapshot that already exists on the VM, and that $cloneSpec.Snapshot has been set to it. Since this option does not clone from a VM’s current state but from one of its snapshots, the clone will not necessarily contain the current state of the source VM (unless you have not powered on the source VM since taking the snapshot). This option is the fastest way to create a clone.

  2. To create a linked clone by copying only the child-most disk (from another linked clone or a VM with snapshots)
    $cloneSpec.Location.DiskMoveType = [Vmware.Vim.VirtualMachineRelocateDiskMoveOptions]::moveChildMostDiskBacking

    This option allows you to create a linked clone that matches the current state of the source VM.

  3. To create full clone by copying all disks (but not snapshot metadata), from the root to the child-most disk, except for non-child-most disks previously copied to the target:
    $cloneSpec.Location.DiskMoveType = [Vmware.Vim.VirtualMachineRelocateDiskMoveOptions]::moveAllDiskBackingsAndAllowSharing

    Note that, although this option preserves delta disks in the clone, it still causes snapshot metadata to be lost, so that it is not possible to required to revert to or even see snapshots in the cloned VM through vSphere Client.

  4. To create full clone that flattens all disks from the parent-most to the child-most disk:
    $cloneSpec.Location.DiskMoveType = [Vmware.Vim.VirtualMachineRelocateDiskMoveOptions]::moveAllDiskBackingsAndDisallowSharing

    This is the type of clone operation that normally happens when using vSphere Client.

(In the above options, if $cloneSpec.Snapshot is null, then “child-most disk” refers to the you-are-here disk. If $cloneSpec.Snapshot is specified, then child-most disk refers to that snapshot’s disk backing.)

Thin provisioned full clones.
Only two values are accepted for VirtualMachineRelocateTransformation: “sparse” or “flat”.

When making a full clone, i.e., when making a clone that contains a new parent-most disk, “sparse” causes the parentmost disk to be created as a thin disk:

$cloneSpec.Location.Transform = [Vmware.Vim.VirtualMachineRelocateTransformation]::sparse

“flat” causes it to be created as a thick disk:

$cloneSpec.Location.Transform = [Vmware.Vim.VirtualMachineRelocateTransformation]::flat

When creating a linked clone, this setting is ignored, because delta disks are always created as sparse disks (which, by the way, are different from thin disks).

Powering on the cloned VM.
You can specify whether you want the cloned VM that you have created to be powered on immediately after creation by setting:

$cloneSpec.powerOn = $true

If you are creating tons of linked clones at the same time (e.g. with the non-blocking “_task” call below), then since linked clones are created so quickly, setting this option to power on all clones immediately after creation means that you will be boot storming your ESX hosts. If you are setting this to true, then it’s best to create and power on your linked clones in small batches.

Cloning to a template.
You can specify whether you want the cloned VM to be marked as a template by setting:

$cloneSpec.template = $true

Calling the CloneVM API.
Lastly, you have two options in PowerCLI for how to call your CloneVM command: you can run it as a blocking operation that returns only after the clone (and power-on) has completed:

$vm.CloneVM( $cloneFolder, $cloneName, $cloneSpec )

or you can run it as a non-blocking task that returns immediately:

$vm.CloneVM_Task( $cloneFolder, $cloneName, $cloneSpec )

The first, blocking version lets you more safely create and power on a huge number of clones from a script, because it waits until each VM’s clone operation has completed before continuing. The second option allows you to create concurrent clone tasks, which will run faster in a loop, but creating and powering on a huge number of clones at once (i.e. a boot storm) can cause your hosts and VMs to have issues and slow down.

Throttling the cloning of VMs.
The best option is avoid boot storms and limit the concurrency by calling CloneVM_Task in small batches, and wait until one batch of clone/poweron operations has completed before starting another. You can use the wait-task cmdlet to wait until a group of tasks has completed.