This is a fairly simple VMWare VM cloning script. I use VMWare Fusion/ESXi for most of my research and neither of these tools have a cloning functionality without paying for it. VMWare Workstation has a built-in function and Fusion is missing that function currently, hopefully they will add it in 4.0. Attached is a really simple proof of concept script for cloning virtual machines. I created a github repo for the script here . I have tested it locally on about 20 different VM's that I have but nothing beats having other people test it. Please let me know if there are any issues.
#!/usr/bin/env ruby -wKU
#Jacob Hamack
#jacob.hammack@hammackj.com
#http://www.hammackj.com
#Usage: clone_vm.rb original/ clone/
def rename_files_by_type ( type , old_vm_name , new_vm_name )
file_of_type = Dir [ "*. #{ type } " ]
file_of_type . each do | old_file_name |
new_file_name = old_file_name . sub ( old_vm_name , new_vm_name )
if old_file_name == new_file_name
next
else
File . rename ( old_file_name , new_file_name )
end
end
end
def file_type ( file )
type = `file ' #{ file } '` . split ( ":" ) [ 1 ]
end
def process_vmdk_files ( old_vm_name , new_vm_name )
vmdk_files = Dir [ "*.vmdk" ]
vmdk_files . each do | file |
type = file_type file
new_file_name = file . sub ( old_vm_name , new_vm_name )
if type =~ /ASCII English text/
File . open ( " #{ new_file_name } " , "w+" ) do | output |
File . open ( " #{ file } " , "r" ) do | input |
while ( line = input . gets )
if line =~ /\" #{ old_vm_name } -s\d\d\d.vmdk\"/
line = line . sub ( old_vm_name , new_vm_name )
elsif line =~ /\" #{ old_vm_name } -\d*-s\d\d\d.vmdk\"/
line = line . sub ( old_vm_name , new_vm_name )
elsif line =~ /parentFileNameHint/
line = line . sub ( old_vm_name , new_vm_name )
else
line = line
end
output . write line
end
end
end
system ( "rm ' #{ file } '" )
elsif type =~ /VMware4 disk image/
File . rename ( file , new_file_name )
else
puts "[!] Broken vmdk: #{ file } "
end
end
end
def process_vmx_file ( old_vm_name , new_vm_name )
File . open ( " #{ new_vm_name } .vmx" , "w+" ) do | output |
File . open ( " #{ old_vm_name } .vmx" , "r" ) do | input |
while ( line = input . gets )
if line =~ /scsi0:0.fileName/
line = line . gsub ( " #{ old_vm_name } " , " #{ new_vm_name } " )
elsif line =~ /displayName/
line = line . gsub ( " #{ old_vm_name } " , " #{ new_vm_name } " )
elsif line =~ /extendedConfigFile/
line = line . gsub ( " #{ old_vm_name } .vmxf" , " #{ new_vm_name } .vmxf" )
elsif line =~ /nvram/
line = ""
elsif line =~ /sched.swap.derivedName/
line = line . gsub ( " #{ old_vm_name } " , " #{ new_vm_name } " )
elsif line =~ /checkpoint.vmState/
line = line . gsub ( " #{ old_vm_name } " , " #{ new_vm_name } " )
else
line = line
end
output . write line
end
end
end
system ( "rm ' #{ old_vm_name } .vmx'" )
end
def process_vmxf_file ( old_vm_name , new_vm_name )
File . open ( " #{ new_vm_name } .vmxf" , "w+" ) do | output |
File . open ( " #{ old_vm_name } .vmxf" , "r" ) do | input |
while ( line = input . gets )
if line =~ /vmxPathName/
line = line . gsub ( " #{ old_vm_name } .vmx" , " #{ new_vm_name } .vmx" )
else
line = line
end
output . write line
end
end
end
system ( "rm ' #{ old_vm_name } .vmxf'" )
end
def process_vmsd_file ( old_vm_name , new_vm_name )
File . open ( " #{ new_vm_name } .vmsd" , "w+" ) do | output |
File . open ( " #{ old_vm_name } .vmsd" , "r" ) do | input |
while ( line = input . gets )
if line =~ /fileName/ or line =~ /filename/
line = line . sub ( " #{ old_vm_name } " , " #{ new_vm_name } " )
else
line = line
end
output . write line
end
end
end
system ( "rm ' #{ old_vm_name } .vmsd'" )
end
file = ARGV [ 0 ]
newfile = ARGV [ 1 ]
if file [- 1 ] == "/"
file = file [ 0 ... file . rindex ( '/' ) ]
end
if newfile [- 1 ] == "/"
newfile = newfile [ 0 ... newfile . rindex ( '/' ) ]
end
#1. Copy existing vm to new path
puts "[*] Cloning #{ file } to #{ newfile } "
system ( "cp -r ' #{ file } '/ ' #{ newfile } '/" )
#clean up the new vm
puts "[*] Clean #{ newfile } "
Dir . chdir ( " #{ newfile } /" )
file = file . gsub ( ".vmwarevm" , "" )
newfile = newfile . gsub ( ".vmwarevm" , "" )
#Remove all of the pointless stuff
system ( "rm *.nvram" )
system ( "rm -rf *.lck" )
system ( "rm -rf Applications/" )
system ( "rm -rf appListCache" )
system ( "rm *.log" )
system ( "rm quicklook-cache.png" )
puts "[*] Fixing disk references"
process_vmdk_files ( file , newfile )
puts "[*] Fixing #{ newfile } .vmx"
process_vmx_file ( file , newfile )
puts "[*] Fixing #{ newfile } .vmxf"
process_vmxf_file ( file , newfile )
puts "[*] Fixing Snapshots"
puts "[*] Fixing *.vmem"
rename_files_by_type ( "vmem" , file , newfile )
puts "[*] Fixing *.vmsn"
rename_files_by_type ( "vmsn" , file , newfile )
puts "[*] Fixing *.vmss"
rename_files_by_type ( "vmss" , file , newfile )
puts "[*] Fixing vmsd"
process_vmsd_file ( file , newfile )