Automation

 View Only
Expand all | Collapse all

Clone VM with powershell

VCPGuru

VCPGuruApr 01, 2010 02:18 PM

  • 1.  Clone VM with powershell

    Posted Apr 01, 2010 10:45 AM

    Hi all, i have two quesitons:

    1. how are you cloning today VMs with powershell (command)= ...?

    2. are you having an errorhandling integrated, f.e. if a VM cloning fails you get an email alert?

    Thank you in advance



  • 2.  RE: Clone VM with powershell

    Posted Apr 01, 2010 10:48 AM

    1. I use most of the time the New-VM cmdlet

    2. I use a general alarm that sends an SNMP trap when any vSPhere task goes wrong.

    But you could easily create an alarm specific for cloning tasks.

    ____________

    Blog: LucD notes

    Twitter: lucd22



  • 3.  RE: Clone VM with powershell

    Posted Apr 01, 2010 10:56 AM

    could you please describe your clone step more detailed?

    f.e.:

    --deletes a VM:

    Get-VM "VMname" |Remove-VM -DeleteFromDisk -Confirm:$false

    BR Simon



  • 4.  RE: Clone VM with powershell

    Posted Apr 01, 2010 11:21 AM

    There are multiple possibilities, depends what exactly you want to do.

    For a simple, straightforward clone without any OS customisation I use

    New-VM -Name <new-vm-name> -VM (Get-VM <model-vm>) -VMHost (Get-VMHost <esx-name>) -Datastore (Get-Datastore <datastore-name>)
    

    If you want to use OS customisation it depends if the options available in the New-OSCustomizationSpec cmdlet are doing what you want to customise.

    Don't forget the New-OSCustomizationNicMapping cmdlet which brings the option to customise the IP address.

    If you want to customise other parameters, you will have to fall back on the CloneVM_Task method from the SDK which offers more option through the VirtualMachineCloneSpec object.

    Do you have any specific customisation requirements ?

    ____________

    Blog: LucD notes

    Twitter: lucd22



  • 5.  RE: Clone VM with powershell

    Posted Apr 01, 2010 11:30 AM

    LucD, you really helped me!

    I would like to do a simple, straightforward clone...now my last problem: Email alert when my simple powershell clone failed....I want to have everything in powershell, clone vm, alert if clone failed, delete vm.I dont like to create the tasks into vCenter.

    Could you help me with this issue too?

    Thanks Simon



  • 6.  RE: Clone VM with powershell

    Posted Apr 01, 2010 11:35 AM

    If I understand you correctly, you don't want an Alarm to be defined in vCenter ?

    That would mean the script has to wait for the completion of the clone process.

    As a consequence you won't be able to clone multiple guest in parallel.

    Is that acceptable ?

    Also note that is quite easy to monitor the actual clone process but that it is not so straightforward to monitor any customisation.

    I understand you're not using any customisation whatsoever. Correct ?

    ____________

    Blog: LucD notes

    Twitter: lucd22



  • 7.  RE: Clone VM with powershell
    Best Answer

    Posted Apr 01, 2010 12:06 PM

    Have a go with this script to see if it does what you want ?

    $fromVMname = <source-vmname>
    $newVMName = <target-vmname>
    $tgtEsxName = <target-esxname>
    $tgtDatastoreName = <target-dsname>
    
    $cloneTask = New-VM -Name $newVMName -VM (Get-VM $fromVMname) -VMHost (Get-VMHost $tgtEsxName) -Datastore (Get-Datastore $tgtDatastoreName) -RunAsync
    Wait-Task -Task $cloneTask -ErrorAction SilentlyContinue
    Get-Task | where {$_.Id -eq $cloneTask.Id} | %{
    	if($_.State -eq "Error"){
    		$event = Get-VIEvent -Start $_.FinishTime | where {$_.DestName -eq $newVMName} | select -First 1
    		$emailFrom = <from-email-address>
    		$emailTo = <to-email-address>
    		$subject = "Clone of " + $newVMName + " failed"
    		$body = $event.FullFormattedMessage
    		$smtpServer = <your-smtp-server>
    		$smtp = new-object Net.Mail.SmtpClient($smtpServer)
    		$smtp.Send($emailFrom, $emailTo, $subject, $body)
    	}
    }
    

    ____________

    Blog: LucD notes

    Twitter: lucd22



  • 8.  RE: Clone VM with powershell

    Posted Apr 01, 2010 02:18 PM

    LucD, you are the man :)!!!

    Nice evening



  • 9.  RE: Clone VM with powershell

    Posted Jul 13, 2011 07:31 PM

    LucD Hi,

    I am trying to automate the process of creating new VMs. I am deploying the VMs from a template I have prepared (has my OS and all software I need). Here are the only customizations I do throughout the wizard (some of which I saved and just reused):

    • Name the VM
    • Choose a datacenter folder
    • Choose a VM host (to spread out the load)
    • Thick provisioning
    • Choose datastorage location (to spread out the load)
    • Assign NetBIOS name same as VM name
    • provide administrator password for auto-login
    • start up the VM after creation
    • VM auto-logs in
    • Computer name is the same as the VM name
    • The new VM gets a new IP

    Can you help me with scripting this? my VM names have the same prefix with consecutive numbers appended (A1-A20)

    I actually tried to use your GPS tool, but when I click on Execute (with one guest "A1" to experiment) I see an hour glass, and nothing happens for a while. I look at vSphere client and the VM was not created. I look at the powershell console and there are no warning/error messages.

    Thanks!



  • 10.  RE: Clone VM with powershell

    Posted Jul 13, 2011 08:25 PM

    I tried to run this manually on vSphere PowerCLI and it is building the VM right now:

    New-VM -VMHost (Get-VMHost 10.20.30.40) -Name VM-1 -Location ‘My System’ -Datastore (Get-Datastore BOX-1) -Template MyTemplate -DiskStorageFormat Thick –OSCustomizationSpec (Get-OSCustomizationSpec ‘MyCustoms’) –RunAsync

    The result I'm getting so far:
    VM-1 was created but was not power-on automatically. I had to turn it on.
    its computer name was not VM-1, which is strange since the OS customization spec I used explicitly tells it to use the VM name for the netbios name. I left it alone for 5 minutes, then came back to it out of cirosity and found that it had rebooted itself automatically, weird. And the computer name is now what I expect VM-1

    At the end of the day I'd like to achieve this:

    foreach(vm host passed in xml or csv file)
    {
      loop 8 times: run the above New-VM command appending a number to the VM- prefix. Also, assign Datastore in round-robin fashion I guess, so I will have to read the datastores into an array from some xml or csv file
    }
    any tips please or code snippets I can piece together to achieve this?


  • 11.  RE: Clone VM with powershell

    Posted Jul 13, 2011 09:43 PM

    I have a 2008 template that I clone from a script and read hosts from a csv file.

    I want to know how to to set the name of the netbios name, ip address whether dhcp or static

    since I have only one spec template, how can i use the csv file and specify different ip addresses from the clone?



  • 12.  RE: Clone VM with powershell

    Posted Jul 14, 2011 05:53 AM

    You can use the Set-OSCustomizationSpec cmdlet to change the hostname.

    You can use the Set-OSCustomizationNicMapping cmdlet for the IP address and mode.

    To use a CSV, you can do something like this

    Import-Csv :C:\vminfo.csv" -UseCulture | %{

       # Your code

    }

    Inside the script you address the values by their columnnames in the CSV.

    If your CSV looks something like this

    Name,IPaddr,IPtype

    "vm1","192.168.1.1","fixed"

    "vm2","192.168.1.2","fixed"

    you can use $_.Name, $_.IPaddr and $_.IPtype inside the foreach loop (alias %)



  • 13.  RE: Clone VM with powershell

    Posted Jul 14, 2011 06:46 PM

    hi lucd

    why do i have to use set-oscustomizationspec to change hostname if I already have a column called "name" and the customization spec is set to change netbios name to vm name? do i need that?

    also how do i set the vm based on which portgroup they should be in?



  • 14.  RE: Clone VM with powershell

    Posted Jul 14, 2011 08:17 AM

    The GPS script was written for an older vSphere version, so it probably needs to be updated for the newer versions.

    Someting for my long list of ToDos :smileywink:

    After a (Windows) machine is cloned it will reboot 1 time automatically and run the sysprep utility.

    With the sysprep utility it will make the requested changes inside the guest OS.

    These changes come from your CustomizationSpec.

    The script you envisage could be something like this

    $dsNames = Import-Csv "C:\dsnames.csv" -UseCulture

    $count = 0

    $vmPrefix = "vmname"

    Import-Csv "C:\vms.csv" -UseCulture | %{

       New-VM -Name ($vmPrefix + $count) -VMHost (Get-VMHost $_.hostname) -Datastore $dsName[$count % $dsNames.Count] ....

       $count++

    }

    The script would read the target datastorenames into an array.

    You loop through a CSV that holds all the ESX(i) hostnames in the format

    "hostname"

    "name1"

    "name2"

    "name3"

    "name4"

    For the round-robin datastore selection I propose to use the module of the number of datastores you provide.

    Example, if you have 3 datastores and you are in iteration 7, the selected datastore will $dsNames[1].

    Does this help ?



  • 15.  RE: Clone VM with powershell

    Posted Jul 14, 2011 07:32 PM

    LucD

    Thanks, this helps a lot, it gets me started on PowerCLI.

    I modified the code a bit. I plan to have 3 csv files. datastores, vmhosts and the actual vm names (instead of playing the game of prefixing, I have another tool that will generate the vm names for me). I will round-robin through the vmhosts and the datastores.

    here's the new snippet:

    $dstores = Import-Csv "C:\vmstuff\dstores.csv" -UseCulture
    $vhosts = Import-Csv "C:\vmstuff\vhosts.csv" -UseCulture
    $count = 0
    Import-Csv "C:\vmstuff\vms.csv" -UseCulture | %{
        $vhost = $vhosts[$count % $vhosts.Count]
        $dstore = $dstores[$count % $dstores.Count]
        #New-VM -Name $_.vm -VMHost (Get-VMHost $host) -Datastore $store ....
        write-host $count $_.vm $vhost $dstore
       
        $count++
    }
    vms.csv looks like:
    vm
    "vm-1"
    "vm-2"
    ...
    "vm-8"
    vhosts.csv look like:
    vhost
    1.2.3.4
    1.2.3.5
    1.2.3.6
    1.2.3.7
    dstores.csv looks like:
    dstore
    "lun-1"
    "lun-2"
    "lun-3"
    "lun-4"
    Now what I really want to do next is this:

    1. Before starting anything, stop and blow up (delete from disk) all existing vms. Wait until the operations are finished, then the script somehow continues
    2. Check the storage capacity of each data store and save it
    3. When picking a data store, make sure it has enough storage (I shouldn't wait for the previous VM to complete, I'll just decrement the remaining free space on that store after I issue a New-VM on it)
    4. Make sure I don't exceed 10 VMs per vhost (maybe I should include this limit in the vhosts.csv ...)
    5. How do I break from the loop if for example I run out of data storage entirely or if I cap all vhosts?
    6. what is the best way to display informational, debug, log message? i'm using write-host but not sure if this is the best-practice way to do it.

    Thanks!



  • 16.  RE: Clone VM with powershell

    Posted Jul 14, 2011 08:33 PM

    Here's the up to date script:

    $dstores = Import-Csv "C:\vmstuff\dstores.csv" -UseCulture
    $vhosts = Import-Csv "C:\vmstuff\vhosts.csv" -UseCulture
    $count = 0
    Import-Csv "C:\vmstuff\vms.csv" -UseCulture | %{
        $vhost = $vhosts[$count % $vhosts.Count].name
        $vhostcap = $vhosts[$count % $vhosts.Count].capacity
        $dstore = $dstores[$count % $dstores.Count].name
        $dstorecap = (get-datastore $dstores[$count % $dstores.Count].name).CapacityMB
        $vm = $_.vm
       
        #New-VM -Name $_.vm -VMHost (Get-VMHost $host) -Datastore $store ....
        $vhostused = [int]$vhosts[$count % $vhosts.Count].used
        $vhostused++
        $vhosts[$count % $vhosts.Count].used = $vhostused
       
        $dstoreused = [int]$dstores[$count % $dstores.Count].used
        $dstoreused += 25000
        $dstores[$count % $dstores.Count].used = $dstoreused
       
        write-host "$count: $vm   $vhost ($vhostused/$vhostcap VMs)    $dstore ($dstoreused/$dstorecap MB)"
       
        $count++
    }

    csv files:

    vm

    "vm-1"

    "vm-2"

    "vm-3"

    "vm-4"

    "vm-5"

    "vm-6"

    "vm-7"

    "vm-8"

    name, capacity, used

    "1.2.3.10", 10, 0

    "1.2.3.11", 10, 0

    "1.2.3.12", 10, 0

    name, capacity, used

    "san_1",0,0

    "san_2",0,0

    "san_3",0,0

    "san_4",0,0

    "san_5",0,0

    my debug output after I connect to the vicenter on PowerCLI and run the script looks like:

    vm-1   1.2.3.10 (1/10 VMs)    san_1 (25000/409344 MB)

    vm-2   1.2.3.11 (1/10 VMs)    san_2 (25000/409344 MB)

    vm-3   1.2.3.12 (1/10 VMs)    san_3 (25000/409344 MB)

    vm-4   1.2.3.10 (2/10 VMs)    san_4 (25000/409344 MB)

    vm-5   1.2.3.11 (2/10 VMs)    san_5 (25000/409344 MB)

    vm-6   1.2.3.12 (2/10 VMs)    san_1 (50000/409344 MB)

    vm-7   1.2.3.10 (3/10 VMs)    san_2 (50000/409344 MB)

    vm-8   1.2.3.11 (3/10 VMs)    san_3 (50000/409344 MB)

    I am missing:

    1. The blowing up of all existing vm before starting up
    2. check to prevent ocercapping a datastore
    3. check for overcapping the hosts

    Any tips and feedback will be appreciated, thanks!!




  • 17.  RE: Clone VM with powershell

    Posted Jul 14, 2011 09:43 PM

    Latest script:

    I implemented 2 and 3.

    $dstores = Import-Csv "C:\vmstuff\dstores.csv" -UseCulture
    $vhosts = Import-Csv "C:\vmstuff\vhosts.csv" -UseCulture
    $countvm = 0
    $countds = 0
    $countvh = 0
    Import-Csv "C:\vmstuff\vms.csv" -UseCulture | %{
        $vm = $_.vm
        $vhost = ""
        $vhostcap = 0
        $vhostused = 0
        $dstorecap = 0
        $dstorefree = 0
        $dsfound = $False
        $error = ""
       
      
        # Check for data storage availability:
        for($d=0; $d -lt $dstores.Count; $d++)
        {
            $countds += $d
            $dstore = $dstores[$countds % $dstores.Count].name
            $dstorecap = (get-datastore $dstores[$countds % $dstores.Count].name).CapacityMB
            $dstorefree = (get-datastore $dstores[$countds % $dstores.Count].name).FreeSpaceMB
            $dstoreused = [int]$dstores[$countds % $dstores.Count].used
            if ($dstorefree -gt 25000)
            {
                $dsfound = $True
                break;
            }
        }
      
        if ( $dsfound -eq $True )
        {
            # Check for host capacity:
            $vhfound = $False
            for($h=0; $h -lt $vhosts.Count; $h++)
            {
                $countvh += $h
                $vhost = $vhosts[$countvh % $vhosts.Count].name
                $vhostcap = $vhosts[$countvh % $vhosts.Count].capacity
                $vhostused = [int]$vhosts[$countvh % $vhosts.Count].used
               
                if($vhostused -lt $vhostcap)
                {
                    $vhfound = $True
                    break;
                }
            }      
           
            if ( $vhfound -eq $True )
            {
                #New-VM -Name $_.vm -VMHost (Get-VMHost $host) -Datastore $store ....
                $vhostused++
                $vhosts[$countvh % $vhosts.Count].used = $vhostused
               
                $dstoreused = [int]$dstores[$countds % $dstores.Count].used
                $dstoreused += 25000
                $dstores[$countds % $dstores.Count].used = $dstoreused
               
                $message = "OK"
            }
            else
            {
                $message = "NOT ENOUGH POWER (!)"
            }
        }
        else
        {  
            $message = "NOT ENOUGH STORAGE (!)"
            #$dstoreused = $dstores[$countds % $dstores.Count].used
        }
       
        write-host "$count: $vm   $vhost ($vhostused/$vhostcap VMs)    $dstore ($dstorefree/$dstoreused/$dstorecap MB)   $message"   
       
        $countvm++
        $countds++
        $countvh++
    }

    What I will need to do is build up the New-VM cmdlet with my parameters and actually execute this on a real environment and see how it goes.

    I am still missing to implement an easy way to blow up all of the existing VMs.

    Any tips or feedback will be appreciated.
    Thanks



  • 18.  RE: Clone VM with powershell

    Posted Jul 19, 2011 12:31 AM

    LucD Hi,

    How do I make the new VM power on automatically? now I have to power it manually. Is there an option I am missing? I'm running this commandlet. vCenter 4.1

    New-VM -VMHost (Get-VMHost MyHost) -Name MyVM -Location ‘My System’ -Datastore (Get-Datastore MyBox)-Template MyTemplate -DiskStorageFormat Thick –OSCustomizationSpec (Get-OSCustomizationSpec ‘My Custom’) –RunAsync -Confirm:$False

    Thanks!



  • 19.  RE: Clone VM with powershell

    Posted Jul 19, 2011 05:33 AM

    On the New-VM cmdlet there is no option to start the guest, but you can use the Start-VM cmdlet.

    You can use the pipeline, something like this

    New-VM ... | Start-VM -Confirm:$false


  • 20.  RE: Clone VM with powershell

    Posted Jul 19, 2011 05:49 AM

    Fascinating! i'll try it tomorrow when i'm near the tools.
    It seems like New-VM executes on its own thread kind of if by pipelining start-vm it'll make this work, given that I have –RunAsync in there.



  • 21.  RE: Clone VM with powershell

    Posted Jul 19, 2011 05:55 AM

    Didn't notice the -Runasync on the New-VM cmdlet. In this case you can not use the pipeline.

    Have a look at my About Async tasks, the Get-Task cmdlet and a hash table post.

    It uses RunAsync and in line 16 you can see how the script starts the guest, provided the New-VM completes successfully.



  • 22.  RE: Clone VM with powershell

    Posted Jul 19, 2011 04:11 PM

    LucD, thank you, this works great!!



  • 23.  RE: Clone VM with powershell

    Posted Apr 12, 2012 12:45 AM

    Hi sOltanOBreens,

    I am trying to implement a script with similar features.... Could you please share your last version to try it in my enviroment? Thanks for your help :smileyhappy: