Menu

Virtual Geek

Tales from real IT system administrators world and non-production environment

VMware PowerCLI Clone and Deploy VM from template in vCenter

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": "Administrator@vsphere.local",
    "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.

TemplateNewVMNameNewVMFolderNewVMClusterNumCpuCoresPerSocketMemoryGBNewVMNetworkNewVMDataStoreNewVMIPv4NewVMSubnetNewVMGatewayNewVMDNS1NewVMDNS2NewVMUserNameNewVMPasswordNewVMDomainNewVMDomainUserNameNewVMDomainPassword
Wakanda_Windows_01TestVMtestvmsBifrost226VM NetworkStarLord_Datastore01192.168.34.9024192.168.34.1192.168.34.11192.168.34.12Administrator123456vcloud-lab.comvcloud-lab\vjanvi123456

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.

VMware vsphere vCenter esxi powercli powershell set-networkadapter clone deploy virtual machine new-vm powershell vmware.powercli restart-vmguest invoke-vmscript rename-computer add-computer.png

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

Go Back

Comment

Blog Search

Page Views

11275430

Follow me on Blogarama