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
