«

»

Sep 06

PowerCLI Script to Start VMs in a Predefined Order

Had a great discussion with some students of the ICM class last night about virtualizing things like domain controllers and vCenter Servers. Of course my thought is virtualize them all.

The discussion lead to what happens if you lose everything, say in the event of a power failure or something like that. We did not get deep into designing the infrastructure correctly (outside of the fact you should design the environment so that this never happens) to make sure things like that do not happen, instead we focused on the “Well what if it did?” Basically forget all the things that should be done to prevent it from happening and focus on what to do if it does.

Of course there is a manual way to do it by connecting to each host one by one and finding the VMs that need to be started and start them, not a big deal in a small 3 or 4 host environment but what if there are 10, 20, 100, or more hosts. Manually connecting to each host to find the VMs could take a lot of time. In an outage like that where application users and owners are probably screaming, the faster things are brought back online the better. So, why not automate the process with a PowerCLI script to start up VMs in order of dependencies? Start up things like the domain controllers and such first, then start up database servers and the like, and finally start up vCenter. Once vCenter is up and running you can then manage the rest of the start up from there.

So I put together a PowerCLI script to do just that. My PowerCLI scripting is a bit rusty and the script found here PowerCLI – find out the host on which VMs are running when vCenter is down helped me get started and I built on it from there.

Instead of passing parameters to the script the hosts and VMs to start are predefined variables: $ESXiHosts is the list of hosts to connect to, $StartFirst is the list of VMs to start up first, $StartSecond is the list of VMs to start up second, $StartThird is the list of VMs to start up last, and $WaitTime is the amount of time in seconds to wait between starting each group of VMs. When the script is run there is a prompt for the root credentials for the ESXi hosts (all of the ESXi hosts defined in $ESXiHosts must have the same root credentials). After the connection is established to each of the hosts, the VMs defined in each start up list are then found, and if the VM is powered off it is powered on. Once completed the script disconnects from the hosts and exits.

Here’s the script:

#Start up VMs in a predefined dependency order if vCenter is unavailable
#Only attempts to start VMs that are in a powered off state

#List of ESXi Hosts
#All hosts in list must have the same root credentials
# "ip of host1", "ip of host2","ip of host3",...
$ESXiHosts = "xxx.xxx.xxx.xxx","xxx.xxx.xxx.xxx"

#List of VM Inventory Names to Start First
#Virtualized domain controllers, DHCP Servers, or DNS Servers that other services depend on
# "VMInventoryName","VMInventoryName",...
$StartFirst = "vDC01","vDC02"

#List of VM Inventory Names to Start Second
#Virtualized database servers that support the vCenter databases
# "VMInventoryName","VMInventoryName",...
$StartSecond = "vDB01","vDB02"

#List of VM Inventory Names to Start Third
#Virtualized vCenter Server since other dependencies have been started
# "VMInventoryName","VMInventoryName",...
$StartThird = "vCenter-VM"

#Amount of time to wait (in seconds) between each start list of VMs
$WaitTime = "60"

#Prompt for ESXi root Credentials
$ESXiCreds = Get-Credential root

#Connect to each host defined in $ESXiHosts
Connect-viserver -Server $ESXiHosts -Credential $ESXiCreds

#If no host connections exit
if ($DefaultVIServer -eq $null) {
    Write "No host connected. Exiting"
    Exit
}

Function Start-ListofVMs($vms) {
 foreach ($vm in $vms) {
  Write "`n  ----Starting `"$vm`"..."
  Get-VM -Name $vm | Where-Object {$_.PowerState -eq "PoweredOff"} | Start-VM |  Format-Table -autosize Name, Powerstate, VMHost | Out-String
 }
 Write "`n Waiting for $WaitTime Seconds for started VMs to stabilize..."
 Start-Sleep -s $WaitTime
}

Write "`n Starting VMs in Start First List: $StartFirst"
Start-ListofVMs $StartFirst

Write "`n Starting VMs in Start Second List: $StartSecond"
Start-ListofVMs $StartSecond

Write "`n Starting VMs in Start Third List: $StartThird"
Start-ListofVMs $StartThird

Write "`n Done - Disconnecting from $ESXiHosts"
Disconnect-VIServer -Server * -Force -Confirm:$false
Exit

Works pretty well in the lab but I am sure there are a lot of things that could be done to make it better. For example instead of setting a wait time between start lists a function could check to make sure VMware Tools is running in the started VMs before it continues to the next list but this is a good start (could be an assignment for the advance class…. hmmm….).

Discussions like this with students is one of the primary reasons I really enjoy teaching. I plan to demonstrate how the script would work in class next Thursday.

Thoughts or feedback is appreciated…

About the author

vHersey

Hersey Cartwright is an IT professional with extensive experience designing, implementing, managing, and supporting technologies that improve business processes. Hersey is Solutions Architect for SimpliVity covering Virginia, Washington DC, and Maryland. He holds the VMware Certified Design Expert (VCDX-DV #128) certification. Hersey actively participates in the VMware community and was awarded the VMware vExpert title in 2016, 2015, 2014, 2013, and 2012. He enjoys working with, teaching, and writing about virtualization and other data center technologies. Follow Hersey on Twitter @herseyc

3 comments

  1. ron

    I would like to use this for a cluster order on restart…. how would this change the script vs VMlist 1, 2, 3???
    EX – start all VMs in a cluster vs all VMs
    Start the management cluster
    Start the dev cluster
    Start the prod cluster

    1. vHersey

      Have not tested but you could probably use Get-VM -Location to set the different VM lists.

      For example:

      $StartFirst = Get-VM -Location | Select Name

      $StartSecond = Get-VM -Location | Select Name

      etc…

      This would only work if vCenter is available.

      Hope that helps.

      Hersey

  2. The2nd

    Great Article..

    What alarm did you use to trigger your script? I’ve tried many of them, but can’t find the correct one to invoke this script during a host failure.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

3 × one =