VM cloning PowerShell script

Be the first to like.

If you need to clone a VM, in an automated and scheduled fashion, the script below might help.

The variables on top allow you to specify the source VM name, how its clone will be called, the target VMware ESX host (even though, of course, the clone won’t be switched on), Datastore and vCenter Folder.

The script will refuse to run unless a clone already exist and it’s switched off, meaning that you’ll have to create the first one yourself. At each execution, if everything looks good, the previous clone will be deleted and a new one will take its place. Any exception will be caught and written in a log file. I use curl.exe to pipe this log file to a centralized alerting system: a small Ruby app that will alert us if anything wrong happens (errors, missed runs, …) with the various batch scripts we’ve got scattered around. I’ll probably blog about it later on.

For any unattended vCenter login/authentication you’ll need a credential store file. Have a look here to learn how to create one. Suitably protect this file because the password it contains is simply obfuscated (using a reversible algorithm) and not encrypted.

Run the script with:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -PSConsoleFile “C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\vim.psc1” c:\scripts\vmname-clone.ps1

$logfile         = 'c:\scripts\vmname-clone.log'
$clonename       = 'vmname-clone'
$credentialsfile = 'c:\scripts\vmname-clone.credentials.xml'
$clonesourcevm   = 'vmname'
$clonehost       = ''
$cloneds         = 'NFSSLOW01'
$clonefolder     = 'Foldername'

function log {
    "$($args -join ' ')" | Out-File $logfile -Encoding ASCII -Append
Clear-Content $logfile

$vm = ''
$timestamp=$(Get-Date -f yyyyMMdd-HH:mm:ss)
log "start: $timestamp"
try {
    $c = Get-VICredentialStoreItem -file "$credentialsfile"
    Connect-VIServer -Server $c.Host -User $c.User -Password $c.Password -ErrorAction Stop
    $vm = Get-VM -name $clonename
    if ($vm.PowerState -ne 'PoweredOff') {
        throw 'PreviousCloneIssues'
    } else {
        log "removing: $vm"
        Remove-VM -ErrorAction Stop -DeleteFromDisk:$true -Confirm:$false $vm
        log "cloning: in progress"
        New-VM -VM "$clonesourcevm" -VMHost "$clonehost" -Name $clonename -Datastore "$cloneds" -Location "$clonefolder" -ErrorAction Stop;
    $timestamp=$(Get-Date -f yyyyMMdd-HH:mm:ss)
    log "done: $timestamp"
catch {
    if (($_.Exception.GetType().FullName -eq 'System.Management.Automation.RuntimeException') -and
        ($_.FullyQualifiedErrorId -eq 'PreviousCloneIssues')) {
        log "error: Clone not found or not Powered Off, refusing to remove it"
    } else {
        log "error: unexpected"

# c:\scripts\curl.exe -s -X PUT --data-binary "@c:\scripts\vmname-clone.log"