PowerShell is very powerful object-orientated programming language inWindows, the comparable counterpart in Unix/Linux is Python.
I couldn’t find a PowerCLI script to clone Linux and assign ip addresses to multiple adapters so I decided to write my own.
If you are new to Vsphere PowerCLI, you may need to check
my previous post to learn how to connect to vi-server via PowerCLI at first.
There are 2 scripts:
discover-info.ps1 # Discovery information of target viserver/ESX host and generate template file to be used for clonevm.ps1
vmclone.ps1 #clone after read information from template file generated by discover-info.ps1 script
The scripts has been tested in VMware vSphere PowerCLI 4.0 for VMs in ESX 3.5/ESX4.0 managed by Virtual Center Server.
Scripts in action
[vSphere PowerCLI] D:\Temp> .\discover-info.ps1
Discovered ESX hosts:esx01 esx02
Please enter target ESX hostname: esx01
..
Template file: vmdata.txt has been generated. Edit the file then run 'clonevm.ps1 -f file-name' to start cloning
[vSphere PowerCLI] D:\Temp> cat vmdata.txt (after customization)
============
####---------------- Discovered information
#PortGroups='Service Console' 'vlan-01' 'vlan-02'
#Folders='host' 'Discovered Virtual Machine' 'Datacenters' 'vm'
#DataStores= 'nfs_storage' 'esx01:storage1'
#resourcepools=Name: Resources ID:ResourcePool-resgroup-7 Name: Resources ID:ResourcePool-resgroup-65
####----------------
####----------------Customize your VM values using the template
esxhost=esx01
##Resource pool id is NOT required for using virtual machine as source, but IS required for using template as source
#resourcepoolid=
#vm means Virtual Machine; vt means template ( resourcepoolid is required for vt)
SrcName=vm,linuxtemplate
DstName=pstest1
##Use vm as folder if no user folders defined
Folder=vm
DataStore=nfs_storage
##Gateway is optional, enter - to skip this value
##Networkadapter type is optional (Auto choosen for guest OS) , enter - to skip this value
##Supported adapter types: e.g e1000, Flexible, Vmxnet, EnhancedVmxnet
Network=EnhancedVmxnet,vlan-01 ,172.19.1.1,255.255.248.0,172.19.1.10 ; -,vlan-02,172.20.1.1,255.255.255.0,-
DNS=10.1.1.1,10.1.1.2
Domain=example.com
#Poweron=yes
####----------------
[vSphere PowerCLI] D:\Temp> .\clonevm.ps1 -f .\vmdata.txt
==> Retrieving info for source VM: linuxtemplate
==> Starting clone process ...
4% 10% 16% 21% 27% 33% 38% 45% 51% 57% 62% 68% 74% 79% 85% 91% %
Completed Task: Task-task-2366
==> Checking new VM ...
Name PowerState Num CPUs Memory (MB)
---- ---------- -------- -----------
pstest1 PoweredOff 1 4096
==> Removing existing network adapters ...
==> Adding 2 new network adapters ...
..
==> Customizing guest OS ...
%
Completed Task: Task-task-2370
==> Checking new VM ...
pstest1 PoweredOff 1 4096
Discover-info.ps1 download
# *Execute the script in a live PowerCLI VIsserver session*
# Generate template file to be used for clonevm.ps1
# DATE: 12 Oct 2010
# Author: http://honglus.blogspot.com
$template_file="vmdata.txt"
$hosts=get-vmhost | foreach { $_.name }
write-host "Discovered ESX hosts: $hosts"
switch ($hosts.length) {
0 { write-host "no ESX host found! exiting.. " ; exit}
1 { $esxhost=$hosts[0] }
default {
$esxhost=read-host "Please enter target ESX hostname"
if ( -not $($hosts -contains "$esxhost") ) { write-host "Unknown host: '$esxhost', exiting.. " ; exit }
}
}
$pgs=Get-VirtualPortGroup -vmhost $esxhost | foreach { "'$_'" }
$folders=get-folder | foreach { "'$_'" }
$dss=get-datastore -vmhost $esxhost | foreach { "'$_'"}
$rspool=get-resourcepool | foreach { "Name: " + $_.name + " ID:" + $_.id }
write-output "
####---------------- Discovered information
#PortGroups=$pgs
#Folders=$folders
#DataStores= $dss
#resourcepools=$rspool
####----------------
####----------------Customize your VM values using the template
esxhost=$esxhost
##Resource pool id is NOT required for using virtual machine as source, but IS required for using template as source
#resourcepoolid=
#vm means Virtual Machine; vt means template ( resourcepoolid is required for vt)
SrcName=vm,clone1
DstName=guest1
##Use vm as folder if no user folders defined
Folder=vm
DataStore=data_store
##Gateway is optional, enter - to skip this value
##Networkadapter type is optional (Auto choosen for guest OS) , enter - to skip this value
##Supported adapter types: e.g e1000, Flexible, Vmxnet, EnhancedVmxnet
Network=adapter-type,port-group1,ip-address1,net-mask1,gateway1 ; EnhancedVmxnet,port-group2,ip-address2,net-mask2,gateway2 ; ...
DNS=dns1,dns2
Domain=example.com
Poweron=yes
####----------------
" | tee $template_file
write-host "Template file: $template_file has been generated. Edit the file then run 'clonevm.ps1 -f file-name' to start cloning"
clonevm.ps1 download
# *Execute the script in a live PowerCLI VIsserver session*
##### Clone VM for Linux guest
#Read information from template file generated by discover-info.ps1 script
#Set target host/datastore for Clone ;Start Clone
#Delete existing adapters; add new adapters; Customize guest OS; powerone VM (Optional)
#DATE: 12 Oct 2010
#Author: http://honglus.blogspot.com
if ( ( $args.count -ne 2 ) -or ( $args[0] -ne "-f" ) ) { write-host "Usage: .\program -f template-filename" ; exit}
$file1=$args[1]
function Retrieve-Values {
$strings=$args[0]
$item=$args[1]
$line=[string] ($strings | select-string -pattern "$item")
$line=$line.trim()
return $line.Substring( $line.LastIndexOf("=")+1 )
}
function wait-for-task {
if ( $args[0] -eq $null ) {write-host "failed " ;exit }
$tskid=$args[0]
$progress=get-task -status running | foreach { if ( $_.id -eq $tskid ) { $_.PercentComplete } }
while ( $progress -ne $null ) {
sleep 30
$progress=get-task -status running | foreach { if ( $_.id -eq $tskid ) { $_.PercentComplete} }
write-host "$progress% " -nonewline
}
write-host ""
write-host "Completed Task:" $tskid
}
$lines=get-content $file1 -ErrorAction stop | select-string -notmatch "(^#|^$)" -ErrorAction stop
$s_esxhost=Retrieve-values $lines "esxhost"
$s_rspoolid=Retrieve-values $lines "resourcepoolid"
$s_srcname=Retrieve-values $lines "SrcName"
$s_dstname=Retrieve-values $lines "Dstname"
$s_folder=Retrieve-values $lines "Folder"
$s_datastore=Retrieve-values $lines "DataStore"
$s_domain=Retrieve-values $lines "Domain"
$s_network=Retrieve-values $lines "Network"
$s_poweron=Retrieve-values $lines "Poweron"
$s_dns=Retrieve-values $lines "DNS"
$s_dns=$s_dns.split(",")
$array_temp=$s_network.split(";")
$nic_cnt=$array_temp.count
#Initialize hash table
$h_network=@{atype=(1..$nic_cnt); pgroup=(1..$nic_cnt); ip=(1..$nic_cnt); mask=(1..$nic_cnt); gateway=(1..$nic_cnt) }
For ($i=0; $i -lt $nic_cnt ; $i++) {
$array_temp2=$array_temp[$i].split(",")
if ( $array_temp2.count -ne 5 ) { write-host "Expected the number of values for network is 5, given" $array_temp2.count ; exit}
$h_network.atype[$i]=$array_temp2[0].trim()
$h_network.pgroup[$i]=$array_temp2[1].trim()
$h_network.ip[$i]=$array_temp2[2].trim()
$h_network.mask[$i]=$array_temp2[3].trim()
$h_network.gateway[$i]=$array_temp2[4].trim()
}
$vmclonespec_host = New-Object VMware.Vim.VirtualMachineCloneSpec
#### Customize Target host /Target datastore
$vmclonespec_host.location = New-Object VMware.Vim.VirtualMachineRelocateSpec
$vmclonespec_host.location.host = (Get-vmHost -Name $s_esxhost | Get-View).MoRef
$vmclonespec_host.location.datastore = (Get-Datastore -Name $s_datastore| Get-View).MoRef
if ( $s_rspoolid.length -gt 0 ) {
$vmclonespec_host.location.pool= (Get-ResourcePool -id $s_rspoolid -ErrorAction stop|get-view).MoRef
}
#### Customize Guest OS
$vmclonespec_os= New-Object VMware.Vim.CustomizationSpec
## Identity for Linux
$vmclonespec_os.identity= New-Object VMware.Vim.CustomizationLinuxPrep
$vmclonespec_os.identity.hostname= New-Object VMware.Vim.CustomizationFixedName
$vmclonespec_os.identity.hostname.name= $s_dstname
$vmclonespec_os.identity.domain=$s_domain
#GlobalIPSettings
$vmclonespec_os.GlobalIPSettings = New-Object VMware.Vim.CustomizationGlobalIPSettings
$vmclonespec_os.GlobalIPSettings.dnsServerList=$s_dns
$vmclonespec_os.GlobalIPSettings.dnsSuffixList=$s_domain
# adapter mapping
for ( $i=0; $i -lt $nic_cnt; $i++ ) {
$vmclonespec_os.NicSettingMap += @(New-Object VMware.Vim.CustomizationAdapterMapping)
$vmclonespec_os.NicSettingMap[$i].Adapter = New-Object VMware.Vim.CustomizationIPSettings
$vmclonespec_os.NicSettingMap[$i].Adapter = New-Object VMware.Vim.CustomizationIPSettings
# FixedIP
$vmclonespec_os.NicSettingMap[$i].Adapter.Ip = New-Object VMware.Vim.CustomizationFixedIp
$vmclonespec_os.NicSettingMap[$i].Adapter.Ip.IpAddress = $h_network.ip[$i]
$vmclonespec_os.NicSettingMap[$i].Adapter.SubnetMask = $h_network.mask[$i]
if ( $h_network.gateway[$i] -ne "-" ) {
$vmclonespec_os.NicSettingMap[$i].Adapter.Gateway = $h_network.gateway[$i]
}
}
$s_srcname_pre=$s_srcName.substring(0,3)
$s_srcname=$s_srcname.Substring( $s_srcname.LastIndexOf(",")+1 )
# Template or Virtual Machine from which the guest will be cloned
write-host "==> Retrieving info for source VM: $s_srcname"
if ( $s_srcname_pre -eq "vm," ) {
$svm = Get-View (get-vm $s_srcname -ErrorAction stop ).ID
}
else {
$svm = Get-View (get-template $s_srcname -ErrorAction stop ).ID
}
$tfld = Get-Folder -Name $s_folder -ErrorAction stop | Get-View
write-host "==> Starting clone process ... "
$taskid=$svm.CloneVM_Task($tfld.moref,$s_dstname,$vmclonespec_host) | foreach {$_.value}
Wait-for-Task "Task-$taskid"
write-host "==> Checking new VM ..."
get-vm $s_dstname -ErrorAction stop
write-host "==> Removing existing network adapters ... "
$adapter = Get-NetworkAdapter -VM "$s_dstname" -ErrorAction stop
if ( $adapter -ne $null ) { Remove-NetworkAdapter -NetworkAdapter $adapter -confirm:$false }
write-host "==> Adding " $nic_cnt "new network adapters ... "
for ( $i=0; $i -lt $nic_cnt; $i++ ) {
if ( $h_network.atype[$i] -ne "-" ) {
New-NetworkAdapter -Type $h_network.atype[$i] -NetworkName $h_network.pgroup[$i] -VM $s_dstname -StartConnected -ErrorAction stop
}
else {
New-NetworkAdapter -NetworkName $h_network.pgroup[$i] -VM $s_dstname -StartConnected -ErrorAction stop
}
}
write-host "==> Customizing guest OS ... "
$newvm = Get-View (get-vm $s_dstname -ErrorAction stop ).ID
$taskid=$newvm.CustomizeVM_Task($vmclonespec_os) | foreach {$_.value}
Wait-for-Task "Task-$taskid"
write-host "==> Checking new VM ..."
sleep 4
get-vm $s_dstname -ErrorAction stop
if ( $S_poweron -eq "yes" ) { start-vm $s_dstname }
Related Documents:
1.
vSphere PowerCLI Quick Start
2.
Master-PowerShell
3.
VMware vSphere Web Services SDK 4.0 (Supported languages: PowerShell C# JAVA Perl )