You can customize and use the following sample script to clone any number of virtual machines (VMs).
To copy and paste the script content without page breaks, use the HTML version of this topic, available from the Horizon 7 documentation page at https://docs.vmware.com/en/VMware-Horizon-7/index.html.
Script Input
This script reads one input file, which is described in Input File for the Sample PowerCLI Scripts to Deploy Linux Desktops. This script also interactively asks for the following information:
- IP address of the vCenter Server
- Administrator login name for the vCenter Server
- Administrator password for the vCenter Server
- Clone type, which can only be full
- Whether to disable a vSphere VM console
Script Content
<# Create Clones from a Master VM The Tool supports creation of Full clone from Master VM. #> #------------------------- Functions ------------------------- function GetInput { Param($prompt, $IsPassword = $false) $prompt = $prompt + ": " Write-Host $prompt -NoNewLine [Console]::ForegroundColor = "Blue" if ($IsPassword) { $input = Read-Host -AsSecureString $input = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($input)) } else { $input = Read-Host } [Console]::ResetColor() return $input } function IsVMExists () { Param($VMExists) Write-Host "Checking if the VM $VMExists already Exists" [bool]$Exists = $false #Get all VMS and check if the VMs is already present in VC $listvm = Get-vm foreach ($lvm in $listvm) { if($VMExists -eq $lvm.Name ) { $Exists = $true } } return $Exists } function Disable_VM_Console() { Param($VMToDisableConsole) $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $extra = New-Object VMware.Vim.optionvalue $extra.Key="RemoteDisplay.maxConnections" $extra.Value="0" $vmConfigSpec.extraconfig += $extra $vm = Get-VM $VMToDisableConsole | Get-View $vm.ReconfigVM($vmConfigSpec) } function Delete_VM() { Param($VMToDelete) Write-Host "Deleting VM $VMToDelete" Get-VM $VMToDelete | where { $_.PowerState –eq "PoweredOn" } | Stop-VM –confirm:$false Get-VM $VMToDelete | Remove-VM –DeleteFromDisk –confirm:$false } #------------------------- Main Script ------------------------- $vcAddress = GetInput -prompt "Your vCenter address" -IsPassword $false $vcAdmin = GetInput -prompt "Your vCenter admin user name" -IsPassword $false $vcPassword = GetInput -prompt "Your vCenter admin user password" -IsPassword $true $cloneType = GetInput -prompt 'Clone Type ("full")' -IsPassword $false $disableVMConsole = GetInput -prompt 'Disable vSphere VM Console ("yes" or "no", recommend "yes")' -IsPassword $false "-----------------------------------------------------" $csvFile = '.\CloneVMs.csv' # Check that user passed only full clone if (($CloneType.length >0) -and ($CloneType -ne "full")) { write-host -ForeGroundColor Red "Clone type supports only 'full' (case sensitive)" exit } if (($disableVMConsole.length >0) -and ($disableVMConsole -ne "yes" -or $disableVMConsole -ne "no")) { write-host -ForeGroundColor Red "Disable vSphere VM Console supports only 'yes' or 'no' (case sensitive)" exit } #check if file exists if (!(Test-Path $csvFile)) { write-host -ForeGroundColor Red "CSV File $CSVFile not found" exit } # Connect to the VC (Parameterize VC) #Connect to vCenter $VC_Conn_State = Connect-VIServer $vcAddress -user $vcAdmin -password $vcPassword if([string]::IsNullOrEmpty($VC_Conn_State)) { Write-Host 'Exit since failed to login vCenter' exit } else { Write-Host 'vCenter is connected' } #Read input CSV file $csvData = Import-CSV $csvFile #$csvData = Import-CSV $csvFile -header("VMName","Parentvm","CustomSpec","Datastore","Host","FromSnapshot","DeleteIfPresent") foreach ($line in $csvData) { "`n-----------------------------------------------------" $VMName = $line.VMName write-host -ForeGroundColor Yellow "VM: $VMName`n" $destVMName=$line.VMName $srcVM = $line.Parentvm $cSpec = $line.CustomSpec $targetDSName = $line.Datastore $destHost = $line.Host $srcSnapshot = $line.FromSnapshot $deleteExisting = $line.DeleteIfPresent if (IsVMExists ($destVMName)) { Write-Host "VM $destVMName Already Exists in VC $vcAddress" if($deleteExisting -eq "TRUE") { Delete_VM ($destVMName) } else { Write-Host "Skip clone for $destVMName" continue } } $vm = get-vm $srcvm -ErrorAction Stop | get-view -ErrorAction Stop $cloneSpec = new-object VMware.VIM.VirtualMachineCloneSpec $cloneSpec.Location = new-object VMware.VIM.VirtualMachineRelocateSpec Write-Host "Using Datastore $targetDSName" $newDS = Get-Datastore $targetDSName | Get-View $CloneSpec.Location.Datastore = $newDS.summary.Datastore Set-VM -vm $srcVM -snapshot (Get-Snapshot -vm $srcVM -Name $srcSnapshot) -confirm:$false $cloneSpec.Snapshot = $vm.Snapshot.CurrentSnapshot $cloneSpec.Location.Host = (get-vmhost -Name $destHost).Extensiondata.MoRef $CloneSpec.Location.Pool = (Get-ResourcePool -Name Resources -Location (Get-VMHost -Name $destHost)).Extensiondata.MoRef # Start the Clone task using the above parameters $task = $vm.CloneVM_Task($vm.parent, $destVMName, $cloneSpec) # Get the task object $task = Get-Task | where { $_.id -eq $task } #Wait for the taks to Complete Wait-Task -Task $task $newvm = Get-vm $destVMName $customSpec = Get-OSCustomizationSpec $cSpec Set-vm -OSCustomizationSpec $cSpec -vm $newvm -confirm:$false if ($disableVMConsole -eq "yes") { Disable_VM_Console($destVMName) } # Start the VM Start-VM $newvm } Disconnect-VIServer $vcAddress -Confirm:$false exit
Script Execution
The following messages are from an execution of the script:
PowerCLI C:\scripts> .\CloneVMs.ps1 Your vCenter address: 10.117.44.17 Your vCenter admin user name: administrator Your vCenter admin user password: ******* Clone Type<"Full"> : Full Disable vSphere VM Console ("yes" or "no", recommend "yes") : yes
The time that the cloning process takes depends on the number of desktop machines and can range from several minutes to several hours. To verify that the process is complete, from vSphere Client, make sure that the last desktop virtual machine is powered on, has its own unique host name, and VMware Tools is running.