Citrix XenApp Rolling Reboot Script


I have a Citrix farm and have written the below PowerShell script to automatically reboot the servers when there are no active connections.


The script would need to be scheduled to run on a Citrix server with the XenApp PowerShell SDK installed

I have setup a scheduled task than runs every hour during none business hours.

Citrix Reboot Script - Triggers
Citrix Reboot Script - Actions


EXCLUDESERVERSA comma separated list of Citrix servers to exclude from the reboot routine.
REBOOTTHRESHOLDHow many days of uptime before a server should be considered for a reboot.
MAXACTIVESESSIONAGEThe maximum time in hours a session is allowed to be active. Any users with an active session over this time will get a 5 min warning and a message before the server reboots.

The Script

Add-PSSnapin "Citrix.XenApp.Commands"

$Global:EXCLUDESERVERS = "CTX-MANAGE-01" #Define which Citrix servers should be excluded from processing. Comma seperated list, short names only, case insensitive (for example "CORPCTX01,CORPCTX02,CORPCTX05")
[int]$Global:REBOOTTHRESHOLD = "1" # Process the server for reboot if it has been up longer than this number of days
[int]$Global:MAXACTIVESESSIONAGE = "15" #Max age for an active session in hours 

$Global:EventLog = New-Object -type System.Diagnostics.Eventlog -argumentlist Application # Creates a global object for logging to the Application event log
$Global:EventLog.Source = "Citrix Reboot Script" # All event logs will be entered with the source of Citrix Reboot Script

$infiniteLoop = $true #DO NOT CHANGE Create an infinite loop variable


#Check to see if the server is online by checking its Citrix load
function ServerOnline {
	$server = "$args" # Create a variable named server from the first passed variable
	$serverload = @(get-xaserverload | Where {$_.ServerName -eq $server}) # Create a query to validate the server is online before proceeding
	foreach ($result in $serverload){
		return $true

#The reboot function
function StartReboot {
	$server = "$args" # Create a variable named server from the first passed variable
	Invoke-Expression "Shutdown.exe /m $server /r /t 300 /f /c ""A auto reboot is about to run please save your work and logoff.""" # Initiate shutdown on remote server
	#Wait for the server to come up and have a load under 5000 before processing the next server
	do {
		$rebooted = $false # Reset variable back to false before checking for reboot
		start-sleep -s 360 # Wait for 360 seconds between checking for reboot completion
		$serverload = @(get-xaserverload | Where {$_.Load -lt "5000"} | Where {$_.ServerName -eq $server}) # Create a query to validate the server is online and load evaluator has reset less than 5000 before proceeding
		foreach ($result in $serverload){
			$rebooted = $true # Server has rebooted and the load evaluator is less than 5000, proceed to next server
			$EventLog.WriteEntry($server + " rebooted properly, load rebalanced. Proceeding with subsequent servers.","Information","811")
	} while ($rebooted -eq $false) # Loop until the server has completed its reboot and load evaluator has returned to idle state
$excludedservers = $GLOBAL:EXCLUDESERVERS.Split(',')

$farmservers = get-xaserver | sort-object -property ServerName # Create an array with all servers sorted alphabetically

	foreach ($farmserver in $farmservers){
		#Work out now minus $MAXACTIVESESSIONAGE
		$time2 = Get-Date -Format "MMM dd yyyy HH:mm"
		$time1 = Get-Date
		$tminus_maxactive = $time1.addhours(-$MAXACTIVESESSIONAGE)
        #Get the current server name
		$server = $farmserver.ServerName
		#If the server is not in the exclude list
		if ($excludedservers -notcontains $server) {
            if (ServerOnline $server) {
				write-host "=========================="
				write-host "SERVER =  " $server
				write-host "=========================="
    			# Get Uptime
    			$os = gwmi Win32_OperatingSystem -computerName $server
    			$lastbootuptime = $os.ConvertToDateTime($os.LastBootUpTime)
    			$starttime = $OS.converttodatetime($OS.LastBootUpTime)
    			$uptime = New-TimeSpan (get-date $Starttime)
				$uptime_days = 0
    			$uptime_days = [int]$uptime.days
				write-host "UPTIME =  " $uptime_days 
    			# Get Active Sessions
    			$session_count = 0    
                #Gives number of active sessions
                $sessions = @(get-xasession | Where {$_.ServerName -eq $server} | Where {$_.State -ne "Listening"} | Where {$_.State -ne "Disconnected"} | Where {$_.SessionName -ne "Console"} | Where {$_.LogOnTime -gt $tminus_maxactive} | group AccountName) # Create a query against server passed through as first variable where protocol is Ica. Disregard disconnected or listening sessions			

				foreach ($session in $sessions) 
				write-host "SESSIONS =  " $session_count
				# Reboot if over the threshold and there are no active sessions
				if ($uptime_days -ge $REBOOTTHRESHOLD -and $session_count -eq 0) {
					write-host "REBOOT = YES"
					$EventLog.WriteEntry("Initiating reboot process on " + $server + " Uptime Days = " + $uptime_days + " Active Sessions = " + $session_count + ".","Information","911")
					StartReboot $server # Initialize the StartReboot function 
				} else {
					write-host "REBOOT = NO"

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.