VMware Cloud Community
shahb
Contributor
Contributor
Jump to solution

Poweroff and Poweron 1000 VMs in Parallel

Hi

I've a maintenance is coming up for which I need to shutdown 1000+ VMs and once the Maintenance is complete, Need to start those VMs back on.

I've a list of 1000 VMs and I can run in for loop but that will take hours to shutdown these VMs and I only have 2 hours of Maintenance window, Can someone please help ?

Here is the script which I got from the community and it works as expected but it runs serially.

foreach ($vmlist in (Get-Content -Path C:\vmlist1.txt)){

$vm = Get-VM -Name $vmlist

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

}

Thanks & Regards

1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

To cover that we can indeed adapt the background job script.

$script = {

   param(

   [string]$VMName,

   [string]$vcServer,

   [string]$vcId

   )


   Import-Module VMware.VimAutomation.Core


   Connect-VIServer -Server $vcServer -Session $vcId


   $vm = Get-VM -Name $VMName

   if($vm.Guest.State -eq "Running"){

  Shutdown-VMGuest -VM $vm -Confirm:$false -RunAsync

   }

   else{

   Stop-VM -VM $vm -Confirm:$false -RunAsync

   }

}


$fileName = '.\input.csv'

$MaxJobs = 10


$jobs = @()


Import-Csv -Path $fileName | ForEach-Object -Process {

   if ($jobs.Count -le $MaxJobs) {

   $job = (Start-Job -Verbose -ScriptBlock $script -ArgumentList $_.VMName, $global:DefaultVIServer.Name, $global:DefaultVIServer.SessionId)

   $jobs += $job

   }

   else {

   Wait-Job -Job $jobs

   $jobs = @()

   }

}


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

View solution in original post

0 Kudos
59 Replies
LucD
Leadership
Leadership
Jump to solution

You can use the Start-Job cmdlet to launch these cmdlets in the background.

You probably want to impose a maximum number of jobs to run in the background, hence the MaxJobs test.

$script = {

   param(

   [string]$VMName,

   [string]$vcId

   )


   Connect-VIServer -Session $vcId


   Get-VM -Name $VMName | Shutdown-VMGuest -Confirm:$false

}


$fileName = '.\input.csv'


$MaxJobs = 10


Import-Csv -Path $fileName | ForEach-Object -Process {

   $jobs = @()

   while ($jobs.Count -le $MaxJob) {

   $jobs += (Start-Job -ScriptBlock $script -ArgumentList $_.VMName, $global:DefaultVIServer.SessionId)

   }

   Wait-Job -Job $jobs

}


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

0 Kudos
shahb
Contributor
Contributor
Jump to solution

Thank you LuCD. Greatly appreciate your quick response.

I'm not great at powercli so please bear me if my questions are silly.

1) When I run it , I get the following error -

pastedImage_0.png

2) Connect-VIServer -Session $vcId ->  Where do we put vCenter name to login to ?

on the other hand, can we just login to vCenter and then just run the script and remove tht line ?

Thanks a lot LuCD for your help.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

1) Sorry, I had a type in there.

The Wait-Job -Job $jobs.Id should have been Wait-Job -Job $jobs.Id.

I corrected the code above.

2) In a background job you don't inherit the connection to the vCenter.

That is why the SessionId is passed to the background job.

And also why we have the Connect-VIServer in there.

To run the script, connect to your vCenter.
Then run the script.

It will pass the SessionId to the background jobs.


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

0 Kudos
shahb
Contributor
Contributor
Jump to solution

Thanks again LuCD

Understood #2 Greatly appreciate it.

I changed the Wait-Job line to Wait-Job -Job $jobs and I still get the same error .

Sorry for bugging you.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Are you sure about the same error?

Just tried it, and it works for me.

Which PowerShell version are you running (check $PSVersionTable)?


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

0 Kudos
shahb
Contributor
Contributor
Jump to solution

Yes, Here is the error -

pastedImage_0.png

pastedImage_1.png

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Can you attach the script as you are running it?


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

0 Kudos
shahb
Contributor
Contributor
Jump to solution

Hi LuCD

Attached.

Thank You

0 Kudos
LucD
Leadership
Leadership
Jump to solution

You are missing a closing brace at the end of the script.
Does your CSV contain a column with the name VMname?

The CSV should look something like this

VMName

vm1

vm2

vm3


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

0 Kudos
shahb
Contributor
Contributor
Jump to solution

Yes, I added VMName and closing brace . Sorry that was missing.

Here is the new error -

pastedImage_0.png

0 Kudos
LucD
Leadership
Leadership
Jump to solution

I have a different version, can you try that one?

$script = {

   param(

   [string]$VMName,

   [string]$vcId

   )


   Connect-VIServer -Session $vcId


   Get-VM -Name $VMName | Shutdown-VMGuest -Confirm:$false

}


$fileName = '.\input.csv'


$MaxJobs = 10


$jobs = @()

Import-Csv -Path $fileName | ForEach-Object -Process {

   if ($jobs.Count -le $MaxJob) {

   Write-Host "Job for $($_.VMName)"

   $job = (Start-Job -Verbose -ScriptBlock $script -ArgumentList $_.VMName, $global:DefaultVIServer.SessionId)

   Write-Host "`tStarted job $($job.Id)"

   Write-Host "`tRunning jobs $($jobs.Count)"

   $jobs += $job

   }

   else {

   Wait-Job -Job $jobs

   $jobs = @()

   }

}


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

0 Kudos
shahb
Contributor
Contributor
Jump to solution

Thanks again for your time and support LuCD

Here is the error after new code -

pastedImage_0.png

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Did none of the Write-Host lines produce any output?


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

0 Kudos
shahb
Contributor
Contributor
Jump to solution

Unfortunately not LuCD

pastedImage_0.png

0 Kudos
LucD
Leadership
Leadership
Jump to solution

That would mean that the following returns nothing.

Can you check?

$fileName = '.\input.csv'

Import-Csv -Path $fileName


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

0 Kudos
shahb
Contributor
Contributor
Jump to solution

Here is my input.csv

VMName

cvp-master1

cvp-master2

its in the same path as the script.

$fileName = '.\input.csv'

Am I doing anything wrong here?

0 Kudos
LucD
Leadership
Leadership
Jump to solution

The relative path starts from your current location.

Did you try the code I just gave?

Does it return the content of the CSV?


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

0 Kudos
shahb
Contributor
Contributor
Jump to solution

Yes, it does

pastedImage_0.png

0 Kudos
LucD
Leadership
Leadership
Jump to solution

I think I found it, there is a typo (missing 's' in $MaxJobs).

The line

if ($jobs.Count -le $MaxJob) {

should say

if ($jobs.Count -le $MaxJobs) {


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

0 Kudos