This script has been written to optimize a scheduled reboot on all VMware VDI desktops. In a VDI environment, you have to keep in mind two important things :
- ESX hosts
- SAN infrastructure
If you plan a reboot on all virtual machines you will impact directly the performance of the ESX servers and/or the SAN storage.
The purpose is to schedule the reboot without impacting both hosts and storages.
This script requires :
- Active Directory cmdlets
- VMware PowerCLI
- Create a folder C:\scripts where the script is located
This script needs to be updated if you use a date format different than “dd.MM.yyyy” (line 118)
This script do the following steps :
- create an array $vdi_list_esx that contains the virtual machine names (the list is created with the cmdlet get-vm from the VMware PowerCLI tool)
- create an array $vdi_list_ads that contains the virtual machine names from the Active Directory
- if the virtual machine name is found in the array $vdi_list_ads :
- check if the virtual machine is alive (WMI ping)
- get the operating system uptime
- create machine pools : each pool contains vdi that does not belong to the same ESX host and the same SAN storage. If the VDI has been restarted in less than 3 days, it is not added to the restart pool.
- send by email a report with a table that contains the virtual machines and scheduled reboot information
- create a Windows scheduled task for each pool to restart the vdi on the next Sunday (the first scheduled task is scheduled at 22:00:00, the others every 15 minutes)
Script :
Import-Module activedirectory Add-PSSnapin VMware.VimAutomation.Core Connect-VIServer -Server 'vSphereServerHostname.domain.local' Function send_mail([string]$message,[string]$subject) { $emailFrom = "task@domain.local" $emailTo = "to@domain.local" $emailCC = "cc@domain.local" $smtpServer = "smtp.domain.local" Send-MailMessage -SmtpServer $smtpServer -To $emailTo -Cc $emailCC -From $emailFrom -Subject $subject -Body $message -BodyAsHtml } function create_pool($array_fct) { for ($i=0; $i -lt $array_fct.length; $i++){ $sched_inc = 1 $vdi_ri = $array_fct[$i].vdi if ($i -eq 0) { $array_fct[$i].pool = $sched_inc } else { # parse existing pools do { $existing_pool_ri = $array_fct | ? { $_.pool -eq $sched_inc } if (($existing_pool_ri -match $array_fct[$i].vHost) -and ($existing_pool_ri -match $array_fct[$i].storage)) { $sched_inc++ $exit_loop = $false } else { $array_fct[$i].pool = $sched_inc $exit_loop = $true } }while ( $exit_loop -eq $false ) } } } $vdi_list_esx = Get-VM | select name,VMHost,DatastoreIdList $vdi_list_ads = get-adobject -Filter {ObjectClass -eq "computer"} -SearchBase "OU=VMwareVDI,DC=domain,DC=local" -SearchScope Subtree -ResultSetSize $null | select Name $array = @() #Clean c:\script content if (gci "c:\scripts\vdi_restart_pool*") { Remove-Item -Force "c:\scripts\vdi_restart_pool*" } #Clean sched tasks $listtasks_arr = @() $listtasks_cmd = "schtasks /query /fo LIST" $listtasks = invoke-expression $listtasks_cmd ($listtasks | select-string "TaskName") | ? { $_ -match "VDI Reboot pool"} | % { $listtasks_arr += $_ } $listtasks_arr = $listtasks_arr | % { ($_ -split "\\" )[1] } $listtasks_arr | % { $myCmd = "SCHTASKS /Delete /F /TN '$_' " $result = invoke-expression $myCmd } foreach ($entry in $vdi_list_ads) { if ($vdi_list_esx.Name -match $entry.Name) { $ad_entry = $entry.Name $strQuery = "select * from win32_pingstatus where address = '" + $ad_entry + "'" $wmi = Get-WmiObject -Query $strQuery if ($wmi.statuscode -eq 0) { try{ $Booted = Get-WmiObject -Class Win32_OperatingSystem -Computer $ad_entry -ErrorAction Stop -WarningAction Stop $uptime = New-TimeSpan -Start $Booted.ConvertToDateTime($Booted.LastBootUpTime) -End (Get-Date) $uptime_str = $uptime.Days $esxhost = ($vdi_list_esx | where { $_.name -match $ad_entry} | select VMHost).VMHost $storage = ($vdi_list_esx | where { $_.name -match $ad_entry} | select DatastoreIdList).DatastoreIdList } catch { $uptime_str=999 } if (($esxhost) -and ($uptime_str -gt 3)) { $Properties = @{vdi=$ad_entry.ToString();vHost=$esxhost.ToString();storage=($storage[0]).ToString();pool="";uptime=$uptime_str;reboot_time=""} $Newobject = New-Object PSObject -Property $Properties $array +=$newobject } } } } $esxhost_arr = $array | select vHost -Unique $storage_arr = $array | select storage -unique create_pool($array) $number_of_pool = ($array |select pool -Unique).count #date calculation : next sunday $date = Get-Date for($i=1; $i -le 7; $i++) { if($date.AddDays($i).DayOfWeek -eq 'Sunday') { $date = get-date $date.AddDays($i) -Hour "22" -Minute "00" -Second "00" break } } $html_head = "<style type='text/css'> table {font-family:verdana,arial,sans-serif;font-size:12px;color:#333333;border-width: 1px;border-color: #729ea5;border-collapse: collapse;} th {font-family:verdana,arial,sans-serif;font-size:12px;background-color:#acc8cc;border-width: 1px;padding: 8px;border-style: solid;border-color: #729ea5;text-align:left;} tr {font-family:verdana,arial,sans-serif;background-color:#d4e3e5;} td {font-family:verdana,arial,sans-serif;font-size:12px;border-width: 1px;padding: 8px;border-style: solid;border-color: #729ea5;} </style>" for ($p=1; $p -le $number_of_pool; $p++){ "Add-PSSnapin VMware.VimAutomation.Core" | Out-File c:\scripts\vdi_restart_pool$p.ps1 "Connect-VIServer -Server 'vSphereServerHostname.domain.local'" | Out-File c:\scripts\vdi_restart_pool$p.ps1 -Append $array | ? { $_.pool -eq $p } | select vdi | % { "restart-vm -vm '"+$_.vdi+"' "+' -Confirm:$false -RunAsync' } | Out-File -Append c:\scripts\vdi_restart_pool$p.ps1 $datetime_start_delta = $p*15 $sched=$date.AddMinutes($datetime_start_delta) $date_to_sched = get-date $sched -format "dd.MM.yyyy" $time_to_sched = ($sched.TimeOfDay.tostring() -split ":")[0..1] -join ":" $myCmd = "schtasks /create /tn 'VDI Reboot pool$p' /sc once /sd $date_to_sched /st $time_to_sched /F /RL HIGHEST /RU domain\username /RP 'Passw0rd' /TR 'powershell -executionpolicy bypass -file c:\scripts\vdi_restart_pool$p.ps1'" $result = invoke-expression $myCmd } $array | % { $pool_number = $_.pool $datetime_start_delta = $pool_number*15 $_.reboot_time = $date.AddMinutes($datetime_start_delta) } $message = "<br><font face='Calibri' color='black'><i>Number of VDI that will be rebooted this sunday : </i><b>" + $array.count + "</b><br>" $message += $array | select vdi,reboot_time,uptime,vHost,storage | ConvertTo-Html -Head $html_head $subject = "[VDI] Scheduled Reboot list" send_mail $message $subject
Reboot task optimization in a VMware Virtual Desktop Infrastructure