VMware Cloud Community
MayurPatel
Expert
Expert
Jump to solution

How to power ON VMs sequencially?

Greetings!

I have a lab/training environment consisting of about  20 plus Windows VMs that I build using MDT.

I have a powershell script which deletes the existing VMs and recreates them with blank disks and attaches each one with the MDT Boot ISO - All good.

What I would like to add is a scripted method of powering up each VM in a sequence starting with the Domain controller and moving down the list, but only after the preceding VM has completed the build and restarted.

Wondering if anyone can shed any light on how to make this work. I must say I have very basic knowledge of powershell - still a novice Smiley Happy

Thanks,

MP

Tags (2)
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

As a kind of skeleton you could use something along these lines.

But it depends how your guest OS customisation is configured.
The moment it writes that guestinfo.deployment value, the VM will be restarted with a max delay of 5 seconds.

$ESXhost = "192.168.1.10"

$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec

$vmConfigSpec.BootOptions = New-Object VMware.Vim.VirtualMachineBootOptions

$vmConfigSpec.BootOptions.BootDelay = $DelayValue

$vmConfigSpec.BootOptions.bootOrder += New-Object VMware.Vim.VirtualMachineBootOptionsBootableCdromDevice

$vmConfigSpec.flags = New-Object VMware.Vim.VirtualMachineFlagInfo

$vmConfigSpec.flags.enableLogging = $false


Import-CSV S:\Automate\labservers.csv -UseCulture |

ForEach-Object -Process {

    $vm = New-VM -VMhost $ESXhost -Name $_.VMName -MemoryMB $_.MemoryMB -NumCPU $_.NumCPU -Version $_.Version -GuestId $_.GuestId -Datastore $_.Datastore -DiskGB $_.DiskGB -DiskStorageFormat "Thin" -Notes $_.Notes -CD

    Get-CDDrive -VM $vm | Set-CDDrive -ISOPath $_.ISOPath -StartConnected $true -Confirm:$false | Out-Null

    Get-NetworkAdapter -VM $vm | Set-NetworkAdapter -NetworkName $_.NetworkName -Type $_.NICType -MacAddress $_.MAC -StartConnected:$true -Confirm:$False | Out-Null

    $vm.ExtensionData.ReconfigVM_Task($vmConfigSpec) | Out-Null

    Start-VM -VM $vm -Confirm:$false


    while(($vm.ExtensionData.Config.ExtraConfig | where{$_.Key -eq 'guestinfo.deployment'}).Value -ne 'finished'){

        sleep 5

        $vm = Get-Vm -Name $vm.Name

    }

    Restart-VMGuest -VM $vm -Confirm:$false

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

0 Kudos
12 Replies
LucD
Leadership
Leadership
Jump to solution

One way of testing if a VM's guest OS ir ready, is by testing the GuestOperationsReady property (in the GuestInfo object).

This requires that you have VMware Tools running on all the VMs.

Another issue you might want to look at is if the guest OS reboots during the startup.

This might happen when the guest OS customizations runs and forces a reboot.

This depends on the type of guest OS.

In that case, you will have to monitor for the reboot, followed by waiting for the GuestOperationsReady property to become $true.

You will also have to define in what order the VMs need to be restarted.

This can be done by listing the VMs, in the correct starting order, in an external file.

For example a CSV.

The following is a skeleton script that could be used as a basis.
Note that you will need to connect (Connect-VIServer) before running the script.

Import-Csv -Path .\startorder.csv -UseCulture |

ForEach-Object -Process {

    $vm = Get-VM -Name $_.Name | Start-VM -Confirm:$false

    while(-not $vm.ExtensionData.Guest.GuestOperationsReady){

        Start-Sleep -Seconds 5

        $vm = Get-VM -Name $vm.Name

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

MayurPatel
Expert
Expert
Jump to solution

Hello Luc, thank you for the reply.

You have pointed out some of the same points that I was somewhat not sure how to check the state.

During the build of each of the Windows VMs, they go through rebooting several times in between during the MDT Litetouch deployment sequence.  And sometimes it could take a while before the next reboot because of application installs. So the GuestOperationsReady method will not be suitable.  I do have the order in which each VM needs to be powered ON. At first I tried to time how long each VM takes to complete the build and place a wait timer for each VM to power ON command but I found sometimes things take longer to complete and it didn't work very well.

I am using a csv file which has an ordered list of VMs which I use for creating the blank VMs on the ESX host. You assisted me on putting a small but very effective snippet together a few years ago and it has served me very well - a big thank you! Below, I have provided the actual script (for others to use) and it would be nice if I could add the logic for powering on each VM into this one simple script.

Add-PSSnapin -Name "VMware.VimAutomation.Core" -ErrorAction SilentlyContinue

   

    # Create LAB Virtual Machines from CSV File

    Set-PowerCLIConfiguration -Scope User -ParticipateInCEIP –confirm:false | Out-Null

    Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$False | Out-Null

    $ESXhost = "192.168.1.10"

    $DelayValue = "5000" # 5 Seconds Boot Delay

   

    $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec

    $vmConfigSpec.BootOptions = New-Object VMware.Vim.VirtualMachineBootOptions

    $vmConfigSpec.BootOptions.BootDelay = $DelayValue

    $vmConfigSpec.BootOptions.bootOrder += New-Object VMware.Vim.VirtualMachineBootOptionsBootableCdromDevice

    $vmConfigSpec.flags = New-Object VMware.Vim.VirtualMachineFlagInfo

    $vmConfigSpec.flags.enableLogging = $false

    connect-VIServer -Server "$ESXHost" -User "root" -Password "VMware1!"   

    Import-CSV S:\Automate\labservers.csv -UseCulture | %{

        $vm = New-VM -VMhost $ESXhost -Name $_.VMName -MemoryMB $_.MemoryMB -NumCPU $_.NumCPU -Version $_.Version -GuestId $_.GuestId -Datastore $_.Datastore -DiskGB $_.DiskGB -DiskStorageFormat "Thin" -Notes $_.Notes -CD

        Get-CDDrive -VM $vm | Set-CDDrive -ISOPath $_.ISOPath -StartConnected $true -Confirm:$false | Out-Null

        Get-NetworkAdapter -VM $vm | Set-NetworkAdapter -NetworkName $_.NetworkName -Type $_.NICType -MacAddress $_.MAC -StartConnected:$true -Confirm:$False | Out-Null

       

        $vm.ExtensionData.ReconfigVM_Task($vmConfigSpec) | Out-Null

       

    }

Labservers.csv

VMName,MemoryMB,NumCpu,Version,GuestId,Datastore,DiskGB,ISOPath,NetworkName,Notes,NICType,MAC

vanADC01,2048,2,v14,windows9Server64Guest,san0480,32,[SAN0480] iso\MDTProduction.iso,vlan199-van-mgt,*** Domain Controller ***,Vmxnet3,00:50:56:00:56:03

What I was thinking of doing is at the end of the VM build and config process, I could create a blank file called "completed.txt" in C:\Windows\Temp and use something like the Invoke-VMScript command to check if the "completed.txt" is present. Or if the example you have provided could be modified to check for the file?

Thanks,

MP

0 Kudos
LucD
Leadership
Leadership
Jump to solution

From my experience, using a sleep time is waiting for accidents to happen.

This will most of the time work, but is bound to fail at some point.

I strongly advise against it.

Checking for a file could be a solution, but then you need to be absolutely sure that this file is created as the last step of the deployment process.

Otherwise you risk finding the file, while there might still be a reboot waiting to take place.

Btw, do you have VMware Tools installed on those VMs in all cases?
In that case one solution might be to use GuestInfo as a way to pass information form within the guest OS to the external script.
Set a value in GuestInfo from within the guest OS and then wait.
The external script waits for the value in GuestInfo to appear, and when it finds the value it restart the guest OS.

Then the external program waits for GuestOperationsReady.

The concept is somewhat the same as creating a file inside the guest OS filesystem.
But the external script depends on running a script inside the guest OS.
A GuestInfo value disappears after a poweroff/reboot, so no risk of doing the same thing twice.

.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
MayurPatel
Expert
Expert
Jump to solution

Luc, thank you for your reply.

Yes, all the VMs have VMTools installed after the OS is deployed by the MDT WinPE and joined to the domain.

I see you point about the importance of the file always being created. If for any reason this file is not created then it would simply stall the installation process. I wish I could do scripting Smiley Sad

I like the idea you have suggested about using the GuestInfo, but am I right to think this method only queries for things like if VMtools is installed or the version number?

Are you suggesting that I install the VMTools as the last item in the task squence? If Yes, I think that might do the trick. Please create a snippet for me to try and improve on it.

Thanks,

MP

0 Kudos
LucD
Leadership
Leadership
Jump to solution

You can set your own variables under guestinfo.

You can launch something like the following command as the last one in your deployment script (make sure to suppress a reboot).

The only requirement is that VMware Tools are already installed and running.

vmtoolsd.exe --cmd "info-set guestinfo.deployment finished"


Then in the monitoring/external script you can do the following to retrieve the value

$vm = Get-VM -Name <MyVM>

$vm.ExtensionData.Config.ExtraConfig |

where{$_.Key -eq 'guestinfo.deployment'} |

select -ExpandProperty Value


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
MayurPatel
Expert
Expert
Jump to solution

I found this power on script from VMware communities, see this link​.

I will be very grateful if you could please help with showing me where I should place the code you devised inside the below example script to make it work.

Thanks!

Add-PSSnapin VMware.VimAutomation.Core 

     $vcenter="<vcenter server>" 

     

    #Connect to vcenter server 

    connect-viserver $vcenter 

     

    #Import vm name and ip from csv file 

    Import-Csv poweredonvms.csv | 

    foreach { 

        $strNewVMName = $_.name 

     

        #Generate a view for each vm to determine power state 

        $vm = Get-View -ViewType VirtualMachine -Filter @{"Name" = $strNewVMName} 

        

        if ($vm.Runtime.PowerState -ne "PoweredOn") { 

               

                Write-Host "Powering On $strNewVMName ----" 

                Get-VM $strNewVMName | Start-VM 

                Sleep 10 

                                           

            #For generating email 

                   $Report += $strNewVMName + " --- Powered on. `r`n" 

           } 

    } 

     

    write-host "Sleeping ..." 

    Sleep 300 

$vm = Get-VM -Name <MyVM>

$vm.ExtensionData.Config.ExtraConfig |

where{$_.Key -eq 'guestinfo.deployment'} |

select -ExpandProperty Value

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Do you actually have any clue what you want to do?

You can't just pick random scripts that vaguely resemble what you want to do.

And then ask to insert code.

This is completely different from where you started, i.e. deploying VMs with an ISO attached.

Where the guest OS installation and customisation would be handled from that ISO.

Did you update your custimisation script, which I presume lives on the ISO, to include the writing to the guestinfo variable?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
MayurPatel
Expert
Expert
Jump to solution

You make a very valid point about if I know what I want to do? And you are right, my plan is to use the same script to build the blank VMs and subsequently power on each VM one by one as each VM build completes the install and config. Forgive me for my ignorance, because I am not very good at scripting, it takes me a lot of time to piece together/modify different code and have to resort to using (trial and error). Although not ideal, to save time I thought - If I use another script which just handles the power on that might do the trick.

Yes, I am going to add the command in the MDT Task sequence towards the end of the build sequence to run the command vmtoolsd.exe --cmd "info-set guestinfo.deployment finished" and reboot for the last time to confirm completion.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

As a kind of skeleton you could use something along these lines.

But it depends how your guest OS customisation is configured.
The moment it writes that guestinfo.deployment value, the VM will be restarted with a max delay of 5 seconds.

$ESXhost = "192.168.1.10"

$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec

$vmConfigSpec.BootOptions = New-Object VMware.Vim.VirtualMachineBootOptions

$vmConfigSpec.BootOptions.BootDelay = $DelayValue

$vmConfigSpec.BootOptions.bootOrder += New-Object VMware.Vim.VirtualMachineBootOptionsBootableCdromDevice

$vmConfigSpec.flags = New-Object VMware.Vim.VirtualMachineFlagInfo

$vmConfigSpec.flags.enableLogging = $false


Import-CSV S:\Automate\labservers.csv -UseCulture |

ForEach-Object -Process {

    $vm = New-VM -VMhost $ESXhost -Name $_.VMName -MemoryMB $_.MemoryMB -NumCPU $_.NumCPU -Version $_.Version -GuestId $_.GuestId -Datastore $_.Datastore -DiskGB $_.DiskGB -DiskStorageFormat "Thin" -Notes $_.Notes -CD

    Get-CDDrive -VM $vm | Set-CDDrive -ISOPath $_.ISOPath -StartConnected $true -Confirm:$false | Out-Null

    Get-NetworkAdapter -VM $vm | Set-NetworkAdapter -NetworkName $_.NetworkName -Type $_.NICType -MacAddress $_.MAC -StartConnected:$true -Confirm:$False | Out-Null

    $vm.ExtensionData.ReconfigVM_Task($vmConfigSpec) | Out-Null

    Start-VM -VM $vm -Confirm:$false


    while(($vm.ExtensionData.Config.ExtraConfig | where{$_.Key -eq 'guestinfo.deployment'}).Value -ne 'finished'){

        sleep 5

        $vm = Get-Vm -Name $vm.Name

    }

    Restart-VMGuest -VM $vm -Confirm:$false

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
MayurPatel
Expert
Expert
Jump to solution

Luc,

Thank you so much for showing me the light Smiley Happy

I will add the command vmtoolsd.exe --cmd "info-set guestinfo.deployment finished" at the end of each of the task sequences of the VM builds and test it out.

Will be in touch shortly.

Thanks!

MP

0 Kudos
MayurPatel
Expert
Expert
Jump to solution

To speed things up, I modified the script and tested it with only 2 VMs in my csv file.

On first try, It successfully created the 1st VM and powered on and it finished the build and on completion, the 2nd VM was created but it failed when powering ON. And I got a "message: "Another task is already in progress." which after checking the VM logs, I found that the next power ON command was sent before the VM creation process had finished. I added a Sleep 10 and that solved the issue.

I want to thank you for help. I never imagined the VMtools could be used for detecting the completion of the VM build. That is why you are the TRUE PowerCLI expert!!

Happy New Year to you and yours!

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Thanks Smiley Happy


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos