This VMware PowerCLI helps cloning and deploying Virtual Machine from template in vCenter Server. I had to write OS customization for Windows 2019 server because due to some reason native customization profile was failing. Here in this script there are 3 files in the script package, first file is vCenterCredentials.json where add vCenter server credentials information to connect vCenter server.
1 2 3 4 5 |
{ "Server": "marvel.vcloud-lab.com", "User": "[email protected]", "Password": "123456" } |
Second file is VM_Data.csv, It contains all the information about VM template which you are going to clone, and add new VM details (such as hardware (network, hard disk), IP etc). For customization of new VM, add info in csv - local administrator account, password to connect cloned VM and additionally add domain name and user, password to join this newly cloned VM into the domain.
Note: For best practices on template use article Create and capture Microsoft Windows server Sysprep template image. Also this script shows customization without using Vmware customization profile.
Template | NewVMName | NewVMFolder | NewVMCluster | NumCpu | CoresPerSocket | MemoryGB | NewVMNetwork | NewVMDataStore | NewVMIPv4 | NewVMSubnet | NewVMGateway | NewVMDNS1 | NewVMDNS2 | NewVMUserName | NewVMPassword | NewVMDomain | NewVMDomainUserName | NewVMDomainPassword |
Wakanda_Windows_01 | TestVM | testvms | Bifrost | 2 | 2 | 6 | VM Network | StarLord_Datastore01 | 192.168.34.90 | 24 | 192.168.34.1 | 192.168.34.11 | 192.168.34.12 | Administrator | 123456 | vcloud-lab.com | vcloud-lab\vjanvi | 123456 |
You can download this script Clone-VMwareVM.ps1 here or it is also available on github.com/janviudapi.
This is the PowerCLI ps1 script file, Make sure you have install VMware.PowerCLI module on PowerShell using command Install-Module VMware.PowerCLI -Scope CurrentUser, Before executing script file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
#Created By: vcloud-lab.com #Owner: vJanvi #Clone a Virtual Machine in VMware vCenter Using PowerCLI Import-Module VMware.VimAutomation.Core $currenPath = Split-Path -parent $MyInvocation.MyCommand.Definition #$PSScriptRoot $vcCreds = Get-Content $currenPath\vCenterCredentials.json | ConvertFrom-Json Connect-VIServer -Server $vcCreds.Server -User $vcCreds.User -Password $vcCreds.Password $newVMInfo = Import-Csv -Path $currenPath\VM_Data.csv foreach ($rawNewVM in $newVMInfo) { $newVM = [PSCustomObject]$rawNewVM $cluster = Get-Cluster -Name $newVM.NewVMCluster $template = Get-Template -Name $newVM.Template $folder = Get-Folder -Name $newVMInfo.NewVMFolder #$portGroup = Get-VirtualPortGroup -Name $newVM.NewVMNetwork $datastore = Get-Datastore -Name $newVM.NewVMDataStore $parameters = @{ Name = $newVM.NewVMName Template = $template Location = $folder ResourcePool = $cluster Datastore = $datastore DiskStorageFormat = 'Thin' #MemoryGB = $newVM.MemoryGB #NumCpu = $newVM.NumCpu #CoresPerSocket = $newVM.CoresPerSocket } Write-Host "Creating VM - $($newVM.NewVMName)" -BackgroundColor DarkGreen New-VM @parameters | Select-Object Name, VMHost, PowerState $vm = Get-VM -Name $newVM.NewVMName $vm | Set-VM -NumCpu $newVM.NumCpu -CoresPerSocket $newVM.CoresPerSocket -MemoryGB $newVM.MemoryGB -Confirm:$false | Select-Object Name, PowerState, NumCpu, CoresPerSocket, MemoryGB $vm | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $newVM.NewVMNetwork -Confirm:$false | Select-Object NetworkName, Parent, MacAddress $vm | Start-VM | Select-Object Name, VMHost, PowerState } Write-Host "Wait for 2 minutes - VM restart in progress" -BackgroundColor DarkRed Start-Sleep -Seconds 120 foreach ($rawNewVM in $newVMInfo) { $vm = Get-VM -Name $rawNewVM.NewVMName $configScript = @" New-Item -Path C:\ -Name Temp -ItemType Directory Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -value 0 Enable-NetFirewallRule -DisplayGroup "Remote Desktop" Disable-NetAdapterBinding -Name 'Ethernet0' -ComponentID 'ms_tcpip6' Get-NetIpAddress -InterfaceAlias Ethernet0 -AddressFamily IPv4 | New-NetIPAddress -IPAddress $($rawNewVM.NewVMIPv4) -PrefixLength $($rawNewVM.NewVMSubnet) -DefaultGateway $($rawNewVM.NewVMGateway) | Select-Object IPAddress, ifIndex Set-DnsClientServerAddress -InterfaceAlias Ethernet0 -ServerAddresses "$($rawNewVM.NewVMDNS1), $($rawNewVM.NewVMDNS2)" Rename-Computer -NewName $($rawNewVM.NewVMName) "@ Write-Host "Configuring VM - $($rawNewVM.NewVMName)" -BackgroundColor DarkRed Invoke-VMScript -VM $rawNewVM.NewVMName -ScriptText $configScript -GuestUser $rawNewVM.NewVMUserName -GuestPassword $rawNewVM.NewVMPassword -ScriptType Powershell $vm | Restart-VMGuest | Select-Object VM, HostName, State, ToolsVersion Write-Host "VM - $($rawNewVM.NewVMName) - Restart in progress - Wait 90 Seconds" -BackgroundColor DarkRed Start-Sleep -Seconds 90 Write-Host "Copy suppliment files to VM - $($rawNewVM.NewVMName)" -BackgroundColor DarkYellow "`$userName = '$($rawNewVM.NewVMDomainUserName)'" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" "`$password = '$($rawNewVM.NewVMDomainPassword)'" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append "# create secure string from plain-text string" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append "`$secureString = ConvertTo-SecureString -AsPlainText -Force -String `$password" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append "# convert secure string to encrypted string (for safe-ish storage to config/file/etc.)" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append "`$encryptedString = ConvertFrom-SecureString -SecureString `$secureString" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append "# convert encrypted string back to secure string" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append "`$secureString = ConvertTo-SecureString -String `$encryptedString" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append "# use secure string to create credential object" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append "`$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList `$userName,`$secureString" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append "Add-Computer -DomainName $($rawNewVM.NewVMDomain) -Credential `$credential #-Restart -Force" | Out-File -FilePath "$currenPath\Suppliments\Join-Domain.ps1" -Append Copy-VMGuestFile -Source $PSScriptRoot\Suppliments\Join-Domain.ps1 -Destination c:\temp\ -VM $vm -LocalToGuest -GuestUser $rawNewVM.NewVMUserName -GuestPassword $rawNewVM.NewVMPassword #-GuestCredential Start-Sleep -Seconds 5 $domainJoinScriptText = @" & 'C:\temp\Join-Domain.ps1' "@ Write-Host "Adding VM $($rawNewVM.NewVMName) to domain - Restarting VM - wait 90 Seconds" -BackgroundColor DarkYellow Invoke-VMScript -VM $rawNewVM.NewVMName -ScriptText $domainJoinScriptText -GuestUser $rawNewVM.NewVMUserName -GuestPassword $rawNewVM.NewVMPassword -ScriptType Powershell Start-Sleep -Seconds 5 $vm | Restart-VMGuest | Select-Object VM, HostName, State, ToolsVersion Start-Sleep -Seconds 90 $deleteFileText = @" Remove-Item -Path 'C:\temp\Join-Domain.ps1' -Force "@ Write-Host "Configuration of VM $($rawNewVM.NewVMName) completed - Removing suppliment files" -BackgroundColor DarkGreen Invoke-VMScript -VM $rawNewVM.NewVMName -ScriptText $deleteFileText -GuestUser $rawNewVM.NewVMUserName -GuestPassword $rawNewVM.NewVMPassword -ScriptType Powershell } Disconnect-VIServer * -Confirm:$false -Force |
Below is the output after cloning template and manual customization of VM.
Useful Articles
Using terraform to clone a virtual machine on VMware vSphere infrastructure
Terraform module clone VMware vSphere Linux and Windows virtual machine
Terraform VMware vSphere Virtual Machine customization clone failed on Windows
Terraform VMware vSphere Virtual Machine cloning Operating system not found
Ansible Deploy a VMware vSphere Virtual Machine from a Template
VMware ansible Error couldn't resolve module community.vmware
Ansible Error couldn't resolve module vmware.vmware_rest
Can not execute kustomize build issue installing Ansible AWX Operator