XenDesktop 7 Rolling Reboot Script

RebootScript_Progress_Report
The below script will perform a rolling reboot of all Servers in a Delivery Group.

It starts by placing servers with no sessions in Maintenance Mode and rebooting them one by one. All servers with active sessions are placed in Maintenance Mode to prevent new sessions. Any servers in Maintenance Mode when the script was started are ignored.

To prevent “breaking” your delivery group, if all servers have active sessions a percentage of servers are “held” for reboot later in the script. Otherwise users would be prevented from logging on. This is 20% by default but can be configured using the –HoldPercent parameter.

Servers in Maintenance Mode do not allow new connections but allow users to reconnect to their sessions.

Virtual Servers are rebooted using Hypervisor, physical are rebooted via Windows OS. By default the script uses the Hypervisor.

Once all servers with no sessions are rebooted, the servers with active sessions are checked every 5 minutes to see if all sessions have cleared down. Once all sessions are logged off the server is rebooted and taken out of Maintenance Mode.

If any servers were “held” for reboot they are rebooted at the end.

The script will end after all servers are rebooted or it times out (24 hours by default). All servers are taken out of maintenance mode after reboot and again at the end of the script to make sure.

Status reports are written to screen and file during various stages of the script. The status report will list: All servers, whether pending, hold, or rebooted, reboot time, whether in Maintenance Mode, and session count.

Below are some ideas I have to add to future versions.

Multiple Desktop Group support
Verification of Parameters. I.E Does desktopgroup exist?
Verification of HoldPercent to prevent using higher than 90%
Start Rebooting Hold Servers when 50% of existing servers rebooted rather than waiting to end of script
Option to force reboot if remaining sessions are RDP.
Timeout in case session hosts don’t register with controller.
Abort script if more than x fail to reregister with controller
Rebooting servers in groups rather than one by one.
Signed script
Disclaimer: Use this script at your own risk. All scripts should be tested on non-Production environments first. I have not tested this script in a large environment yet. Once I have my new lab up and running I will have more capcity to test this.

Full list of syntax and help is available by typing Get-Help  XD7_Rolling_Reboot_V1.ps1

[download id=”1308″]
[download id=”1319″]

<# .SYNOPSIS Reboots XenDesktop Session Host Servers .DESCRIPTION Reboots all XenDesktop Session Host servers in a Desktop Group. Servers with no sessions are rebooted first. Servers with sessions are placed in Maintenance Mode until all sessions are logged off. Can be used with physical or virtual servers. If all servers have active sessions a percentage of servers (default 20%) are held online until all other servers have been rebooted. This is to prevent blocking all logons to the Delivery Group. These servers are then rebooted at the end of the script. If all servers have active sessions and HoldPercent is less than one, script will exit to prevent blocking logons. By default the script will timeout 24 hours after it was started .PARAMETER DeliveryGroup DeliveryGroup Name of DeliveryGroup to apply reboot script to .PARAMETER HoldPercent The percentage of servers to leave online if all servers have active sessions. Default is 20% .PARAMETER OutPath Path for logfiles. Default is My Documents .EXAMPLE PS C:PSScript > XD7_Rolling_Reboot_V1.ps1 -DeliveryGroup “Finance”

Will reboot all the servers via the Hypervisor in the Delivery Group called Finance.
If all servers have active sessions, the last 20% of servers will be
left online and rebooted once all other servers have rebooted.

Log files will be saved to Documents folder of user running the script.
.EXAMPLE
PS C:PSScript > XD7_Rolling_Reboot_V1.ps1 -DeliveryGroup “Finance” -ServerType P

Will reboot all the servers via the Windows Operating System in the Delivery Group called Finance.
If all servers have active sessions, the last 20% of servers will be
left online and rebooted once all other servers have rebooted.

Log files will be saved to Documents folder of user running the script.
.EXAMPLE
PS C:PSScript > XD7_Rolling_Reboot_V1.ps1 -DeliveryGroup “Finance” -ServerType P -HoldPercent 50

Will reboot all the servers via the Windows Operating System in the Delivery Group called Finance.
If all servers have active sessions, 50% of servers will be
left online and rebooted once all other servers have rebooted

Log files will be saved to Documents folder of user running the script.
.EXAMPLE
PS C:PSScript > XD7_Rolling_Reboot_V1.ps1 -DeliveryGroup “Finance” -ServerType P -HoldPercent 50 -TimeOut 18

Will reboot all the servers via the Windows Operating System in the Delivery Group called Finance.
If all servers have active sessions, 50% of servers will be
left online and rebooted once all other servers have rebooted

Script will timeout after 18 hours

Log files will be saved to Documents folder of user running the script.

.EXAMPLE
PS C:PSScript > XD7_Rolling_Reboot_V1.ps1 -DeliveryGroup “Finance” -ServerType P -HoldPercent 50 -Timeout 18 -OutPath “C:temp”

Will reboot all the servers via the Windows Operating System in the Delivery Group called Finance.
If all servers have active sessions, 50% of servers will be
left online and rebooted once all other servers have rebooted.

Script will timeout after 18 hours

Log files will be saved to C:Temp.
.INPUTS
None. You cannot pipe objects to this script.
.OUTPUTS
No objects are output from this script. This script creates a its own logs files
.LINK
https://www.shaunritchie.co.uk
.NOTES
NAME: XD7_Rolling_Reboot_V1.ps1
VERSION: 1.00
AUTHOR: Shaun Ritchie
#>

#Thanks to @jeffwouters and @carlwebster for these parameters. The structure has been lifted from Carl Webster’s XenApp Documentation Script
[CmdletBinding(SupportsShouldProcess = $False, ConfirmImpact = “None”, DefaultParameterSetName = “”) ]

Param([parameter(
Position = 0,
Mandatory=$True)
]
[Alias(“DG”)]
[ValidateNotNullOrEmpty()]
[string]$DeliveryGroup=””,

[parameter(
Position = 1,
Mandatory=$False)
]
[Alias(“ST”)]
[ValidateNotNullOrEmpty()]
[string]$ServerType=”V”,

[parameter(
Position = 1,
Mandatory=$False)
]
[Alias(“PCO”)]
[ValidateNotNullOrEmpty()]
[decimal]$HoldPercent=”20″,

[parameter(
Position = 2,
Mandatory=$False)
]
[Alias(“TO”)]
[ValidateNotNullOrEmpty()]
[int]$TimeOut=”24″,

[parameter(
Position = 3,
Mandatory=$False)
]
[Alias(“OF”)]
[ValidateNotNullOrEmpty()]
[string]$OutFilePath=[environment]::getfolderpath(“mydocuments”)
)

Set-StrictMode -Version 2

Add-PSSnapin Citrix.* -erroraction silentlycontinue

$LessThanOneError = “All Session Host servers had active sessions. HoldPercent was calculated to be less than 1 server, script terminated to prevent blocking logons to the Delivery Group.”
$TimeOutError = “The script did not finish before the timeout and was therefore terminated. All servers have been returned to out of maintenance.”
$HoldPercent = $HoldPercent / 100
$ScriptStarted = Get-Date

Write-Host `r`n “Continual Progress Report is also being saved to” $($OutFilePath) -BackgroundColor Yellow -ForeGroundColor DarkBlue
Write-Host `r`n “Script will timeout after ” $($ScriptStarted.AddHours($TimeOut)) -BackgroundColor Yellow -ForeGroundColor DarkBlue

#Get all servers for specified desktop group and exclude servers alredy in Maintenance Mode

[System.Collections.ArrayList]$Servers = Get-BrokerMachine -DesktopGroupName $DeliveryGroup | Where-Object {$_.InMaintenanceMode -ne “True”}

#Create RebootList Array

[System.Collections.ArrayList]$RebootList = @()

Foreach ($Server in $Servers)
{
$obj = New-Object -TypeName PSObject
$obj | Add-Member -MemberType NoteProperty -Name DNSName -Value $Server.DNSName
$obj | Add-Member -MemberType NoteProperty -Name MachineName -Value $Server.MachineName
$obj | Add-Member -MemberType NoteProperty -Name InMaintenanceMode -Value $False
$obj | Add-Member -MemberType NoteProperty -Name RebootStatus -Value “Pending”
$obj | Add-Member -MemberType NoteProperty -Name RebootTime -Value “”
$obj | Add-Member -MemberType NoteProperty -Name SessionCount -Value $Server.SessionCount
$RebootList += $obj
}

Function Reboot
{
If ($ServerType -eq “V”)
{
New-BrokerHostingPowerAction -MachineName $Server.DNSName -Action Restart | out-null
}
ElseIf ($ServerType -eq “P”)
{
Restart-Computer -ComputerName $Server.DNSName
}
}

Function RebootCheck
{
Do
{
Start-Sleep -s 60
$RegistrationState=Get-BrokerMachine -DesktopGroupName $DeliveryGroup -DNSName $Server.DNSName
}

Until ($RegistrationState.RegistrationState -eq “Registered”)
}

Function CheckProgress
{

If (($RebootList | Where-Object {$_.RebootStatus -eq “Rebooted”} | Measure-Object).Count -eq $RebootList.Count)
{
Foreach ($Server in $RebootList)
{
Set-BrokerMachine $Server.MachineName -InMaintenanceMode $False
$Server.InMaintenanceMode = $False
}
$RebootList | Export-CSV -NoTypeInformation ($OutFilePath + “RebootScriptReport.csv”)
Write-Host “SCRIPT FINISHED: Logs and reports have been saved to” $OutFilePath -BackgroundColor Yellow -ForeGroundColor DarkBlue
Break
}
ElseIf ($ScriptStarted.AddHours($TimeOut) -lt $(Get-Date))
{
Foreach ($Server in $RebootList)
{
Set-BrokerMachine $Server.MachineName -InMaintenanceMode $False
$Server.InMaintenanceMode = $False
}
$RebootList | Export-CSV -NoTypeInformation ($OutFilePath + “RebootScriptReport.csv”)
Write-Host “SCRIPT OVERRAN TIMEOUT AND WAS TERMINATED: Logs and reports have been saved to” $OutFilePath -BackgroundColor Yellow -ForeGroundColor DarkBlue
Out-File -FilePath ($OutFilePath + “RebootScriptLog.Log”) -InputObject $TimeOutError
Break
}
}

Function ReportProgress
{

$d = Get-Date
$Progress = “PROGRESS REPORT issued on ” + $($d.ToShortDateString()) + ” at ” + $($d.ToShortTimeString()) + $($rebootlist |Select-Object MachineName,RebootStatus,RebootTime,InMaintenanceMode,SessionCount| Format-Table | Out-String)
Write-Host $Progress -BackgroundColor Yellow -ForeGroundColor DarkBlue
Add-Content -Path ($OutFilePath + “RebootScriptProgress.txt”) -Value $Progress
}

#If all servers have active sessions, put X% of servers ($HoldPercent) in Hold status to prevent blocking all logons to the Delivery Group

$active=@()
$active = $RebootList | Where-Object {$_.SessionCount -gt 0}
$KeepOnline = [System.Math]::Round(($RebootList.Count) * $HoldPercent)

If ($RebootList.Count -eq ($Active | Measure-Object).Count -and $KeepOnline -lt 1)
{
$LessThanOneError | Out-File ($OutFilePath + “RebootScriptLog.Log”)
Break
}
ElseIf ($RebootList.Count -eq ($Active | Measure-Object).Count)
{
$x = $RebootList.Count -$KeepOnline
Do
{
$RebootList[$x].RebootStatus = “Hold”;
$x++
}
Until ($x -eq $RebootList.Count)
}

#Reboot servers with no active sessions, place other servers in Maintenance Mode

Foreach ($server in $RebootList)
{
$Server.SessionCount = (Get-BrokerMachine -DesktopGroupName $DeliveryGroup -DNSName $Server.DNSName).SessionCount
If ($Server.RebootStatus -ne “Hold” -and $Server.SessionCount -eq 0)
{
Set-BrokerMachine $Server.MachineName -InMaintenanceMode $True
$Server.InMaintenanceMode = $True
Reboot
$Server.RebootTime = Get-Date
RebootCheck
Set-BrokerMachine $Server.MachineName -InMaintenanceMode $False
$Server.InMaintenanceMode = $False
$Server.RebootStatus = “Rebooted”

}
Elseif ($Server.RebootStatus -ne “Hold”)
{
Set-BrokerMachine $Server.MachineName -InMaintenanceMode $True
$Server.InMaintenanceMode = $True
}
ReportProgress
CheckProgress
}

#Check Servers with Active Sessions every 5 minutes, reboot when session count = 0

Do
{
Foreach ($server in $RebootList)
{
$Server.SessionCount = (Get-BrokerMachine -DesktopGroupName $DeliveryGroup -DNSName $Server.DNSName).SessionCount
If ($Server.RebootStatus -eq “Pending” -and $Server.SessionCount -eq 0)
{
Reboot
$Server.RebootTime = Get-Date
RebootCheck
Set-BrokerMachine $Server.MachineName -InMaintenanceMode $False
$Server.InMaintenanceMode = $False
$Server.RebootStatus = “Rebooted”
}
}
ReportProgress
CheckProgress
Start-Sleep -s 300
}
Until (($RebootList | Where-Object {$_.RebootStatus -eq “Pending”} | Measure).Count -eq 0)

#Process servers that were held for reboot

If (($RebootList | Where-Object {$_.RebootStatus -eq “Hold”} | Measure).Count -gt 0)
{
Foreach ($server in $RebootList)
{
If ($Server.RebootStatus -eq “Hold”)
{
Set-BrokerMachine $Server.MachineName -InMaintenanceMode $True
$Server.InMaintenanceMode = $True
Do
{
If (((Get-BrokerMachine -DesktopGroupName $DeliveryGroup -DNSName $Server.DNSName).SessionCount) -eq 0)
{
Reboot
$Server.RebootTime = Get-Date
RebootCheck
Set-BrokerMachine $Server.MachineName -InMaintenanceMode $False
$Server.InMaintenanceMode = $False
$Server.RebootStatus = “Rebooted”
}
ReportProgress
CheckProgress
Start-Sleep -s 300
}Until (($RebootList | Where-Object {$_.RebootStatus -eq “Rebooted”} | Measure).Count -eq $RebootList.Count)

}
}
}

Book a free consultation
and discuss your IT challenges with us