Wilco van Bragt - LinkeIn Wilco van Bragt - Twitter rssa 

How to: Rebootscript XenApp 6.5

Updated 21-12-2011
I found that on several systems a failed ping does not set errorlevel to 1, so hostsavailable won't be updated and the script can fail. I now updated the script with another solution, so a failed ping will end in a failed host in the script.

Introduction

In XenApp 6.5 (which is released at 24 August 2011) the way a Server-based Load Evaluator could be assigned to a server has changed in comparison with previous XenApp version. Till 6.5 it was possible to assign a Load Evaluator directly to a server out of the console or using MFCOM/PowerShell. In 6.5 this option is removed and Load Evaluators can only be assigned using Citrix policies. This has advantage that always the correct Load Evaluator is assigned to a server; however I (and many others) used Load Evaluators to get servers out of the standard load balancing (with keeping the possibility to pick a up a disconnected session or to connect via RDP as an administrator) for troubleshooting, maintenance and reboots. Especially with reboots this works beautifully assigning a Load Evaluator based on scheduling (with the least possible active time as possible at the most quit moment on the farm). 

In this article I will describe how the same result can be achieved, while using the new techniques in XenApp 6.5.

Pre-Configuration

 

As mentioned in the introduction Load Evaluators can only be assigned using Citrix Policies. The setting is located logically in the machine part of the policy settings. Citrix Machine Policies can be assigned to Active Directory OUs or Citrix Worker Groups. Because I don't want to move server between OUs during reboot I have chosen to use Worker Groups. So what I did are the following steps. I created the corresponding Load Evaluators. In this case I created one for the default servers, one Load Evaluator for the Backup Data Collector (which will also host applications) and one load evaluator for the reboot/maintenance windows based on the scheduling rule.

Image

During testing I noticed that a server can be member of none, one or more Worker Groups. To be 100% sure the reboot part will not affect anything else, like Published Applications assigned to a Worker Group.   So for every Load Evaluator I created also a worker group with the same names as the load evaluator (this is not a requirement, but to keep it simple).

Image

The next step is to create the corresponding policies. Again I have chosen to create separate policies for the load evaluator part, so I created a policy for each load evaluator with only configures setting configured: Load Evaluator Name configured with the corresponding Load Evaluator. This policy again is assigned to the just created Worker Group, so everything is combined.

Image

So creating a policy with setting a load evaluator to a Worker Group all the needed configuration is available to create the rebootscript. The big change in comparison with the other previous scripts is that we are not assigning load evaluators as a start but moving a server from one worker group to another. Although it's possible to be member of more Worker Groups and so you could set-up a priority in the policy you only have to add a server to a Worker Group I decided to keep it orderly that a server should only be member of one Load Evaluator based Worker Group.

Reboot Script

So the script starts with determine the current Worker Group the server is member of currently. Because we are using more Worker Groups per server, one for the load evaluator and one for assigning Published Applications/Desktops we need to find out which of the Worker Groups is meant for the Load Evaluator. That's one of the reasons I used the same name convention. When a Worker Group starts with LE that's the Worker Group we need. When we got that Worker Group we are removing the server from that Worker Group and assign the Worker Group for the NoNewLogons load evaluator. Below shown PowerShell script, which I will call out of another CMD script basically because I'm not really experienced with PowerShell, is arranging this.

# Script      : LEtoNoNewLogons.ps1
# Author   : Wilco van Bragt
# Creation Date : 15-8-2011
# Usage      : Change LE to NoNewLogons by moving to another Worker Group
#**************************************************************************
# Date                                                       Version      Scripter     Changes
#------------------------------------------------------------------------
# 7:57 15-8-2011       0.1                WvB                                     Intial Version
# 14:03 15-8-2011    0.2                WvB                                     First Full version
# ***************************************************************************

add-pssnapin citrix.*

$computer=get-content env:computername
$LE="LE_VanBragt_NoNewLogons"

# Determine current Load  Evaluator Worker Group and remove server from that group

$WGCurrent=get-xaworkergroup -ServerName $computer
$WGs=foreach ($objitem in $WGCurrent) {$objitem.WorkerGroupName}
$WG=$WGs | select-string -pattern "LE"

remove-xaworkergroupserver $WG $computer

# Add Computer to NoNewLogons WorkerGroup so new user will be logged on

add-xaworkergroupserver $LE $computer

It's good to know that Citrix policies are using the same refresh period as Active Directory, so it can take up to 90 minutes (by default) for the policy is applied. So the first thing after running the PowerShell script is running a gpupdate to reflect the change of the Worker Groups (and actually assigning a new Load Evaluator). I also create a log file on date (above in the script) to check if everything runs fine and troubleshooting issues. After the server has moved to the NoNewLogon Worker Group users can reconnect to their session, but new sessions will be forwarded to the other servers available in the farm.  Normally I enable the NoNewLogon LE round 18:00/19:00 (or a different time if the company is using time shifts in 24Hour environment) and wait for a specified time interval using the simple ping command. In the example script we wait for six hours before we are going to display messages to the connected users that the server will be rebooted in a time frame.

After the last warning message has been shown to the user the script will read out a file where the available server should be filled in. For every server the script will check if the machine is reachable using ping (think about firewalls disable ICMP request) and if the machine is reachable we will check the IMA services. If the response is not running, we presume that the server is not available. If the number of not available servers is higher than the specified amount, the reboot will be aborted. If enough servers are available the server will be rebooted. In the case the reboot is cancelled we will take the server in production again using another PowerShell script, which I will go into detail a bit later in this article.

@ECHO OFF

GOTO START

*************************************************************************
**
** Script   : Reboot_Server.cmd
** Author                        : Wilco van Bragt
** Creation Date: 15-8-2011
** Usage   : Rebooting Server + Check Servers Online
**
** ***************************************************************************
**
** Date                             Version      Scripter     Change
** -----------------------------------------------------------------------------------------
** 10:50 15-8-2011 0.1               WvB                                     Initial version
** 15:12 15-8-2011 0.2               WvB                                     Addes Cancel PowerShell script
**
*****************************************************************************

:START

                        IF NOT EXIST C:\LOG\RebootCheck MD C:\LOG\RebootCheck 

                        FOR /f "tokens=1-3 delims=0123456789 " %%i in ("%date%") do set d=%%i%%j%%k

                        FOR /f "tokens=1-3 delims=%d%" %%i in ("%date%") do set d=%%i%%j%%k              

                        SET LOGNAME=%~n0-%d%
                        SET LOGFILE=C:\LOG\RebootCheck\%LOGNAME%.log
                        SET LFILES=C:\LocalScripts\_FILES
                        SET SERVERFILE=C:\LocalScripts\_FILES\TerminalServers.txt
                        SET MAXLOSTSERVERS=1

:: Change the LE of the Server to NoNewLogons by changing the Citrix Worker Group

                        ECHO Using PowerShell script to Disable New Logons using LE and Worker Groups >>%LOGFILE%

                        powershell %LFILES%\LEtoNoNewLogons.ps1

                        ECHO Start Gpupdate to force the new LE and Worker Group >>%LOGFILE%

                        gpupdate /force

:: Wait for 6 Hours to start displaying messages to the end user

                        ECHO Wait for 6 Hours to start displaying messages using PING -n 21600
                        ping -n 21600 localhost

 

:DISPLAYMSG

 

                        MSG * /SERVER:%COMPUTERNAME% /time:120 "This server will be restarted in 60 minutes."
                        ECHO At %time% the message 60 Minutes displayed to end-user on server %COMPUTERNAME% >>%LOGFILE%
                        ping -n 1800 localhost

                        MSG * /SERVER:%COMPUTERNAME% /time:120 "This server will be restarted in 30 minutes."
                        ECHO At %time% the message 30 Minutes displayed to end-user on server %COMPUTERNAME% >>%LOGFILE%
                        ping -n 900 localhost

                        MSG * /SERVER:%COMPUTERNAME% /time:120 "This server will be restarted in 15 minutes."
                        ECHO At %time% the message 15 Minutes displayed to end-user on server %COMPUTERNAME% >>%LOGFILE%
                        ping -n 600 localhost

                        MSG * /SERVER:%COMPUTERNAME% /time:120 "This server will be restarted in 10 minutes."
                        ECHO At %time% the message 10 Minutes displayed to end-user on server %COMPUTERNAME% >>%LOGFILE%
                        ping -n 300 localhost

                        MSG * /SERVER:%COMPUTERNAME% /time:120 "This server will be restarted in 5minutes. Please save your work and logoff. You can logon directly again, where you will be forwarded to another server"
                        ECHO At %time% the message 5 Minutes displayed to end-user on server %COMPUTERNAME% >>%LOGFILE%
                        ping -n 300 localhost

                        GOTO :CHECKSERVERSONLINE

 

:CHECKSERVERSONLINE

SET HOSTSNOTAVAILABLE=0

FOR /F "tokens=*" %%G in ('type "%SERVERFILE%"') do call :CheckStatus %%G

IF %HOSTSNOTAVAILABLE% GEQ %MAXLOSTSERVERS% GOTO :CANCEL      

                        ECHO Enough Servers Online to Reboot. Reboot for %COMPUTERNAME% will be excuted now >>%LOGFILE%
                        CALL %SYSTEMROOT%\system32\shutdown.exe /R

                        GOTO :END

:CheckStatus

                        SET TSNAME=%1
                        SET %STATE%==UNKNOWN

DEL %TEMP%\ping.txt

 PING %TSNAME% >%temp%\ping.txt

 FOR /F "tokens=*" %%i in ('FIND /i "Reply" %temp%\ping.txt') DO CALL :LOGCHECK %%i

 IF %RESULT%==NOT_FOUND set /a HOSTSNOTAVAILABLE+=1 & GOTO :EOF

                        FOR /F "tokens=1,2,3,4" %%A IN ('SC.EXE \\%TSNAME% QUERY IMAService ^| FIND /I "STATE"') DO SET STATE=%%D

                        IF NOT %STATE%==RUNNING set /a HOSTSNOTAVAILABLE+=1
                        ECHO %HOSTSNOTAVAILABLE%

GOTO :EOF

:: -------------------------------------------------------------------------
:: LOGCHECK
:: -------------------------------------------------------------------------
:LOGCHECK
 SET VALUE=%*
 IF NOT "%VALUE:~,5%"=="-----" SET RESULT=FOUND
 IF /I "%VALUE:~,5%"=="-----" SET RESULT=NOT_FOUND
 
 GOTO :EOF

:CANCEL

                        ECHO Script has determnied that the at least %MAXLOSTSERVERS% server(s) are not available. Reboot for %COMPUTERNAME% is cancelled >>%LOGFILE%

                        MSG * /SERVER:%RBSERVER% /time:120 "The reboot of server is cancelld. You can keep on working."
                        ECHO At %time% the message Reboot Cancelled is displayed to end-user on server %COMPUTERNAME% >>%LOGFILE%
                        ECHO Put the server back into the corresponding LE Worker Group >>%LOGFILE%                    

                        powershell %LFILES%\LEtoDefaultLE.ps1

                        gpupdate /force

:END

Normally I will use a scheduled task to start the reboot process. In a similar article about rebooting servers (with Kemp Load Balancer) I already described how this can be accomplished, so read that article for more information about creating the scheduled task.

After the reboot

After the server is started up again and for example installation and maintenance tasks are performed we need to remove the server from the NoNewLogon Worker Group and add them to his corresponding Load Evaluator group. I again created a small PowerShell script to accomplish start, which I will start as (a part of) a start-up script. In the script you need to define the name of the server hosting the Backup Data Collector (logically this is only necessary if the BDC also acts as application host and the primary data collector is dedicated in this case) and the corresponding Worker Group names. The scripts checks the computername and if it matches the specified BDC name, the server will be added to the BDC Load Evaluator Worker Group otherwise the defined standard Load Evaluator will be used. Don't forget to run the gupdate /force again; otherwise it can take up to 90 minutes before the load evaluator is actually applied.

# Script      : LEtoDefaultLE.ps1
# Author   : Wilco van Bragt
# Creation Date : 15-8-2011
# Usage      : Change LE to NoNewLogons by moving to another Worker Group
#**************************************************************************
# Date                                                       Version      Scripter     Changes
#------------------------------------------------------------------------
# 14:47 15-8-2011    0.1                WvB                                     Intial Version
#
#***************************************************************************

add-pssnapin citrix.*

$computer=get-content env:computername
$NOLOGONWG="LE_VanBragt_NoNewLogons"
$BDCserver="<<BDCSERVERNAME>>"
$BDCWG="LE_VANBRAGT_BDC"
$STANDARDWG="LE_VANBRAGT_Standard"

# Remove Computer from No New Logons Worker Group

remove-xaworkergroupserver $NOLOGONWG $computer

# Add Computer to his standard LE Worker Group

if ($computer -eq $BDCServer) {add-xaworkergroupserver $BDCWG $computer}
else {add-xaworkergroupserver $STANDARDWG $computer}

Conclusion

With the release of Citrix XenApp 6.5 the way load evaluators are assigned has changed. It's not possible anymore to directly assign a Load Evaluator to a server, but this should be done using Citrix Policies. However in the previous versions I (and many other) used the Load Evaluator for reboots by assigning a specific Load Evaluator to get the server on a nice way out of the farm. In this article I have explained and shown how the same behavior still can be accomplished using policies and Worker Groups.