Updated on 22 December 2015 with some small adjustments (removing old files and wait timeout to check if the server is online again)

Some years ago I already published a reboot script for XenApp 6.5. Also Citrix did a good job to make the reboot possibilities within the Citrix policies more flexible and robust. The only real disadvantage is the possibility to disable the logon possibilities 60 minutes before the real actual reboot take place. However this can be overwritten using a specific registry key, which is not well known or documented (HKLM\Software\Policies\Citrix\IMA\Restart Options\Disable Logons\RebootDisableLogonMinutes. When migrating from XenApp 6.5 to XenApp/ XenDesktop 7.x you will probably be a bit disappointed. In this article I will starting describe the reboot possibilities in XenApp/XenDesktop 7.x out of the box, followed by explaining a script that I have written to satisfy more requirements.

Default Reboot Options in XenDesktop/XenApp 7.x

With the release of XenApp/XenDesktop 7.x Citrix moved to the FMA architecture. As FMA is built with VDI (Client Desktops) as a starting point rebooting schedules were not that important. I think that is probably the reason that the reboot possibilities are limited within the product, especially when you have experiences with XenApp 6.5.

The reboot options are not available within the Citrix policies anymore as in XenApp 6.5. They are now located as the properties of a Delivery Group.

As shown in above figure the options are pretty limited, especially the reboot options are set on a delivery group. Normally you would have all the machines running in production and providing the same functionally in one delivery group. You can configure the reboot schedule to daily or a specific day of a week (in other words the machines will be restarted once a week). In my opinion this is unacceptable in 24x7 environments. However there is additional configuration setting called Restart additional groups every.

This feature is not well documented, happily other people like Bas van Kaam in the article Rebooting your xendesktop 7.x application servers. Summarized this option offers the possibility that XenDesktop/XenApp split the machine in two groups. The groups will be restarted separately with a wait time between the two groups as defined at the option Restart additional groups every. Unfortunate this option from the GUI offers only a wait time of five hours maximum. Again I think this time is way too short for 24x7 environments. I’m also missing an option to place the machine in maintenance mode in advance, preferable again with a configurable time frame between the maintenance mode and actual reboot step.

XenDesktop/XenApp 7.x Reboot Script

As the available Reboot options are not sufficient for 24x7 environments (in my opinion) we needed an alternative. Logically you will search if somebody else already encountered the same problem and build a solution. Shaun Ritchie already created a Rolling Reboot Script for XenDesktop/XenApp 7.x. This is real nice script, but it did not totally fulfill the needs for 24x7 environments. Therefore I created my own XenDesktop/XenApp 7.x Reboot Script. Before explaining what is does and how it works I need to thank Google the people which code was on the Internet already which I re-used or used as inspiration.

The script I created offers the following functionality:

  •           The machines will be divided in two groups based on the last digit of their machine name
  •           Two reboot moments are set (based on the day of the week).
  •           Each machine group will be assigned to one reboot moment
  •           The machines in that group will be put in maintenance mode
  •           The script will wait for the specified time to start the actual reboot process (drain mode)
  •           (Adjustable) Messages will be send to the possible active users from 60 minutes to 5 minutes before the actual reboot process.
  •           The machine will be rebooted

-          Script will check if the machine is registered again and disables the maintenance mode

-          All steps are logged in a log file per day.

Using the script

When you would like to use the script you need to place the script on a Citrix Delivery Controller and let start automatically. I’m using a Scheduled Task to accomplish that. The user starting the script logically needs to have admin rights within the XenDesktop/XenApp infrastructure and at least local admin rights on the VDAs.

The script has several variables that need or could be adjusted. Those are combined below the remark “Define Infrastructure Dependent Variables”. The following variables are available:

  •           $DeliveryGroup: Provide the name of the Delivery Group which machines need to be rebooted (required to change)
  •           $EnableMaintenanceTime: Provide the time between entering the maintenance mode and the actual reboot process (drain mode) in seconds. I entered 21600 second (six hours) as a default.
  •           $Tempdir: Enter a directory where the temporary files created and used within the script. I entered C:\Temp as default.
  •           $Logdir: Enter a directory where the log files will be stored. I entered C:\Temp as default.
  •           $EvenDays: Provide the days of the week the server that have an even number as last digit will be restarted. I entered Sunday, Tuesday and Thursday as default.
  •           $OddDays: Provide the days of the week the server that have an oddnumber as last digit will be restarted. I entered as default: "Monday","Wednesday","Friday"
  •           $UserWarningMessagePart1: First part of the user warning message that the machine will be restarted. Remember that between Part 1 and Part the actual minutes will be entered. I use as default "Please save your work and log-off. This machine will be restarted in"
  •          $UserWarningMessagePart2: Second part of the user warning message, which will be shown after the actual minutes in the message. I use as default "minutes."

The actual script

After those values are configured you are ready to use the script. I will explain what the script does and how this is logged in the log file.

The script starts with reading the required variables. For one of the variable the day of the week is determined. The script starts with determine based on the day of the week variable that even or odd servers need to rebooted (in the code I assume that on Saturday no servers will be rebooted) and will be add to a variable.

After that the script reads out the servers in the Delivery Group that are NOT in a maintenance mode and have the registered state (these servers will actual run production) and saved in a temporary file. This file will be read and for each machine based on the last digit (Thanks Remko Weijnen for the line of code) if the server is even or odd. Last step of this part is comparing the outcome of the digit with the earlier variable that odd or even servers will be rebooted. If this is match the machine will be added to a second temporary file.

This file will be read again and the machine in this file will be placed in maintenance mode. Now the script will wait for the set time at the variable EnableMaintenanceTime. After this wait time the script continues with sending messages to possible active users that the machine will be rebooted.

After those messages the machine will rebooted actually. After the restart the script will check if the machine is registered again within the XenDesktop/XenApp infrastructure. If after four attempts the machine still is not registered a message will be added in the log file that the registration failed. If the machine registers successfully the maintenance mode will be disabled.

For every steps information is stored in a log file as shown in below figure (for testing purposes I removed the wait moments).

Hopefully you find the script useful, it can be used for free (would be nice if you keep my as the original creator). I’m not an excellent PowerShell scripter, so if you have any additions or improvement please let me know.

Reboot Script XenDektop/XenApp 7.x:

#---------------------------------------------------------------------

# Script: RebootXenApp7VDA.ps1

# Reboot Script for two groups of XenApp 7.x VDAs (for 24x7 environments)

# Creator: Wilco van Bragt

# Creation Date: 27-11-2014

#---------------------------------------------------------------------

# Version: 0.1

# By: Wilco van Bragt

# Date: 27-11-2014

# Changes: Initial Release

#---------------------------------------------------------------------

# Import Modules

#---------------------------------

add-pssnapin Citrix.* -erroraction silentlycontinue

# Define Infrastructure Dependent Variables

#---------------------------------

$DeliveryGroup="<<DELIVERYGROUPNAME>>"

$EnableMaintenanceTime=21600

$Tempdir="C:\temp"

$Logdir="C:\temp"

$EvenDays="Sunday","Tuesday","Thursday"

$OddDays="Monday","Wednesday","Friday"

$UserWarningMessagePart1="Please save your work and log-off. This machine will be restarted in"

$UserWarningMessagePart2="minutes."

# Define Script Variables

#---------------------------------

$exe="C:\Windows\System32\msg.exe"

$ScriptStart=Get-Date

$Date=Get-Date -format M.d.yyyy

$DayofWeek=(get-date).dayofweek

$Logfile=$Logdir+"\RebootLog"+$Date+".log"

$ServerstoReboot=$TempDir+"\ServerstoReboot.txt"

# Functions

#---------------------------------

Function LogWrite

{

   Param ([string]$logstring)

   Add-content $Logfile -value $logstring

}

# Check on old working files and remove those if exists
#---------------------------------
if ((test-path $TempDir"\VDAs.txt"))  
    {LogWrite "Old VDAs.txt found, file will me removed."    
    Remove-Item $TempDir"\VDAs.txt"  }
 if ((test-path $ServerstoReboot))  
    {LogWrite "Old $ServerstoReboot found, file will me removed."    
    Remove-Item $ServerstoReboot  }

# Start RebootScript

#---------------------------------

LogWrite "Script started at $ScriptStart"

# Determine based on the Day of the week even or odd servers are booted

#---------------------------------

If ($DayofWeek -eq "Saturday")

{LogWrite "Today is Saturday, no servers will be rebooted"

   $EndScriptDate=Get-Date

   LogWrite "Script ended on $EndScript"

   exit

}

If ($EvenDays -contains $DayofWeek)

{$Reboot="Even"

   LogWrite "Day of the week is $DayofWeek, even servers need to be rebooted"

   }

If ($OddDays -contains $DayofWeek)

   {$Reboot="Odd"

   LogWrite "Day of the week is $DayofWeek, odd servers need to be rebooted"

   }

  

# Catch the VDAs in the Delivery Group which are not in maintenance mode

#---------------------------------

LogWrite "Determine which VDAs in the Delivery Group which are not in maintenance and have the state registered"

Get-BrokerMachine -DesktopGroupName "$DeliveryGroup" | Where-Object {($_.InMaintenanceMode -ne "True") -And ($_.RegistrationState -eq "Registered")} | select MachineName | Add-Content $TempDir"\VDAs.txt"

if (!(test-path $TempDir"\VDAs.txt"))

                {LogWrite "No machines are found. Script will quit."

                $EndScriptDate=Get-Date

   LogWrite "Script ended on $EndScript"

                exit

                }

$VDAs=Get-Content $TempDir"\VDAs.txt"

LogWrite "The following servers are available in the Delivery Group: $VDAs"

LogWrite "Next step is to determine which servers will be rebooted this day"

#Trim the VDA Name and determine if the server should be rebooted

#---------------------------------

foreach ($line in $VDAs)

                { $DeviceName=$line.split('=')[1]

                    $DeviceName=$DeviceName.Trim("}")

                $DeviceLastNumber = [int]"$(($DeviceName)[-1])"

     If([bool]!($DeviceLastNumber%2))

       {$DeviceNumber="Even"}

     else

       {$DeviceNumber="Odd"}

     If ($Reboot -eq "Even" -And $DeviceNumber -eq "Even")

         {$DeviceName | Add-Content $ServerstoReboot

           LogWrite "$DeviceName is added to the list of servers to reboot"

         }                  

     If ($Reboot -eq "Odd" -And $DeviceNumber -eq "Odd")

         {$DeviceName | Add-Content $ServerstoReboot

           LogWrite "$DeviceName is added to the list of servers to reboot"

         }    

       $DeviceName=$null

   }

if (!(test-path $ServerstoReboot))

                {LogWrite "No machines are added to list to reboot. Script will quit."

                $EndScriptDate=Get-Date

   LogWrite "Script ended on $EndScript"

                exit

                }             

               

#Set Maintenance Mode for servers who will reboot

#---------------------------------

$RebootServers=Get-Content $ServerstoReboot

foreach ($line in $RebootServers)

     {$DeviceName=$line

     Set-BrokerMachineMaintenanceMode -InputObject $DeviceName -MaintenanceMode $True

     LogWrite "$DeviceName is set in maintenance mode"

     $DeviceName=$null

     }

     LogWrite   "All machines are set in Maintenance. Script will wait for $EnableMaintenanceTime seconds to continue."

     start-sleep -s $EnableMaintenanceTime

#Send Messages to possible active users

#---------------------------------

foreach ($line in $RebootServers)

       {$DeviceName=$line

       $DeviceName=$DeviceName.split('\')[1]

       & $exe * /Server:$DeviceName /time:120 $UserWarningMessagePart1 "60" $UserWarningMessagePart2

       LogWrite "Warning message 60 minutes is send to possible active users on machine $DeviceName"

         }

start-sleep 1800

foreach ($line in $RebootServers)

       {$DeviceName=$line

       $DeviceName=$DeviceName.split('\')[1]

       & $exe * /Server:$DeviceName /time:120 $UserWarningMessagePart1 "30" $UserWarningMessagePart2

       LogWrite "Warning message 30 minutes is send to possible active users on machine $DeviceName"

       }

start-sleep 1200

foreach ($line in $RebootServers)

       {$DeviceName=$line

       $DeviceName=$DeviceName.split('\')[1]

       & $exe * /Server:$DeviceName /time:120 $UserWarningMessagePart1 "10" $UserWarningMessagePart2

       LogWrite "Warning message 10 minutes is send to possible active users on machine $DeviceName"

       }

start-sleep 300

foreach ($line in $RebootServers)

       {$DeviceName=$line

       $DeviceName=$DeviceName.split('\')[1]

       & $exe * /Server:$DeviceName /time:120 $UserWarningMessagePart1 "5" $UserWarningMessagePart2

       LogWrite "Warning message 5 minutes is send to possible active users on machine $DeviceName"

       }

start-sleep 300

#Execute Reboot and check if servers are back on-line

#---------------------------------

LogWrite "Actual reboot process will start now"

foreach ($line in $RebootServers)

       {$CTXDeviceName=$line

         $DeviceName=$line

         $DeviceName=$DeviceName.split('\')[1]

         LogWrite "Restart command is send to machine $DeviceName"

         Restart-Computer -Computername $DeviceName -Force -Wait -For PowerShell -Timeout 600

         LogWrite "Start-up process of $DeviceName is being checked."

         $count=$null

         Do

           {   start-Sleep 30

                 $ServerStatus=Get-BrokerMachine -MachineName $CTXDeviceName

               $count=$count+1

           }

         Until (($ServerStatus.RegistrationState -eq "Registered") -or ($count -eq "4"))

          

         IF ($ServerStatus.RegistrationState -eq "Registered")

         {LogWrite "Machine $CTXDeviceName has successfully registered. MaintenanceMode will be turned off."

                               Set-BrokerMachineMaintenanceMode -InputObject $CTXDeviceName -MaintenanceMode $False

                               }

         ELSE

         {LogWrite "Machine $CTXDeviceName is not successfully registered. Please check this machine."}

         }

#Clean-up temporary files         

#---------------------------------

Remove-Item $ServerstoReboot

Remove-Item   $TempDir"\VDAs.txt"  

                              

$EndScriptDate=Get-Date

LogWrite "Script finished at $EndScriptDate"