At one of my customers we build a XenApp 6.5 environment, where the XenApp Session Hosts were running on local storage of the Hypervisor (VMware ESX 5.5). At this customer the hypervisor and Citrix XenApp were maintained by separate teams. The hypervisor team was used to use shared storage and the vMotion capabilities of ESX for their maintenance tasks on the ESX host during daily operations. However now the virtual machines were running local storage this technique could not be used anymore and the hypervisor team found it difficult to fulfill their maintenance tasks.
After some discussion we agreed that the process should be as easy as possible (without less inference of the XenApp team) and that it should be possible to do the maintenance during daily operations. The first step was adding additional capacity, so maintenance during the business hours was possible. Secondly I wrote a set of small simple scripts that the maintenance can be done without less interaction between the teams and user impact is minimal. In this article I would like to share those scripts with you including explaining what they are doing.
Script 1: Determine the XenApp Session Hosts
For these ESX maintenance activities I actually created a total of four scripts. Each script is part of the whole process. The first script is pretty straight forwarded. First the FQDN name of the vCenter server needs to be provided and a filename and location need be entered to store the XenApp Session Hosts in for the next script. During the script the hypervisor administrator will enter the FDQN of the ESX hosts on which he would like to execute maintenance. For each ESX host provided the VMs will be determined and stored in the earlier provided file. More ESX hosts can be entered during the script, till the administrator decided to add no more.
#--------------------------------------------------------------------- # Script: GetXenAppSessionHosts.ps1 # Determine which XenApp Session Hosts are running on the provided ESX host # Creator: Wilco van Bragt # Creation Date: 15-10-2014 #--------------------------------------------------------------------- # Version: 0.1 # By: Wilco van Bragt # Date: 15-10-2014 # Changes: Initial release #--------------------------------------------------------------------- # # Requirements: # - Scripts needs to run on server with VMware ESX PowerShell cmdlets #--------------------------------------------------------------------- # Import Modules #--------------------------------- Add-PSSnapin VMware.VimAutomation.Core # Provide vCenter en connect to this VIserver #--------------------------------- $VIServer=Read-Host "Please enter the FQDN of the vCenter server" Connect-VIServer $VIServer # Define variable #--------------------------------- $strQuit="Yes" # Provide file to store XenApp Session Hosts #--------------------------------- $XenAppSessionHostFile=Read-Host "Please enter the filename and path to store XenApp Session Hosts" # Determine the VMs on this host and store those names in a texfile #--------------------------------- Do { $ESXHost=Read-Host "Please enter the FQDN of the ESX host which will go in maintenance" get-vmhost "$ESXHost" | Get-VM | Add-Content "$XenAppSessionHostFile" $strQuit= Read-Host "Do want to enter another ESX host?" } Until ($strQuit -eq "No") |
Script 2: Place Sessions Host in maintenance and shutdown
The second script is the most intelligent of the whole scripts. In this script the earlier collection Citrix XenApp Session Host will be placed in maintenance mode and shutdown the VM when no users’ sessions are running anymore (or after seven hours and several warning messages). When all VMs are shutdown the hypervisor administrator can start his maintenance activities.
Before you can use the script, please check the variable $ServertoWorkerGroup contains a location that is available on your machine.
The script starts with asking the location and filename in which the Citrix XenApp Session hosts are stored. This file will be read and for each server in the file the LogonMode will be changed to Prohibit New Logons. Secondly the server will be checked if it’s located in a reboot Worker Group and removed from this worker group, so the server is not restarted during this script. This information is also stored in a file, so we can reconfigure the Worker Group settings later. This customer had created several worker groups where to each WG a different reboot schedule policy was assigned to. Logically you can remove this part if this is not the case in your infrastructure. For administration purposes (the XenApp admin can see quickly which server is in maintenance) the machine is placed in a “maintenance” worker group.
When these steps are finished the script will wait for one hour and checks if there are still sessions on the machine. If there are no sessions running anymore, the machine will be shut down. If there are still sessions the script will check on active sessions on hour later. This step is repeated every hour, when after seven hours still active sessions are running on the machine a message is send to the users and the machine will be shut down. At the end of the script all machines are shut down and the hypervisor administrator can start his maintenance activities.
#--------------------------------------------------------------------- # Script: SessionHostsinMainteance.ps1 # Take XenApp Session Hosts offline for ESX maintenance # Creator: Wilco van Bragt # Creation Date: 10-10-2014 #--------------------------------------------------------------------- # Version: 0.1 # By: Wilco van Bragt # Date: 10-10-2014 # Changes: Initial release #--------------------------------------------------------------------- # Textfile with XenApp Session Hosts is required (preferred generated by PowerCLI) # Requirements: # - Scripts needs to run on server with Citrix PowerShell cmdlets # - WorkerGroups defined in variabeles $MaintenanceWG and $WGReboot should be available #--------------------------------------------------------------------- # Import Modules #--------------------------------- add-pssnapin Citrix.* #Define Variables #--------------------------------- $WGReboot="Reboot" $MaintenanceWG="MaintenanceWG" $ServertoWorkerGroup="c:\Temp\ServertoWorkerGroup.txt" $exe="C:\Windows\System32\msg.exe" #Provide the file with the XenApp Session Hosts, that should be taken off-line #--------------------------------- $SessionHostFile=Read-Host "Please enter the path and name of the file containing the XenApp Session Hosts" #Read Session Hosts names, disable logon, remove server out of the WG reboot group and add to WG maintenance group #--------------------------------- $SessionHosts=Get-Content $SessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line Set-XAServerLogOnMode -LogOnMode ProhibitNewLogOns -ServerName $DeviceName $WGCurrent=Get-XAWorkerGroup -ServerName $DeviceName $WGs=foreach ($objitem in $WGCurrent) {write-host $objitem if ($objitem -match "$WGReboot") { Add-Content $ServertoWorkerGroup "$DeviceName,$objitem" remove-xaworkergroupserver $objitem $DeviceName } } add-xaworkergroupserver $MaintenanceWG $DeviceName } #Wait on hour and check if there are (still) sessions running on the server #If there are no sessions shutdown the machine, else wait #--------------------------------- Clear-Variable DeviceName start-sleep -s 3600 foreach ($line in $SessionHosts) { $DeviceName = $Line $sessions=get-xaserverload -ServerName $DeviceName | select Load $sessions = $sessions -split('=') $load = $Sessions[1] $load=$load.Trim("}") if ($load -eq 0) {Stop-Computer $DeviceName $ServersinUse=Get-Content $SessionHostFile | Where-Object {$_ -ne $DeviceName} $ServersinUse | Out-File $SessionHostFile } } #Wait on hour and check if there are (still) sessions running on the server #If there are no sessions shutdown the machine, else wait #--------------------------------- Clear-Variable DeviceName start-sleep -s 3600 $SessionHosts=Get-Content $SessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line $sessions=get-xaserverload -ServerName $DeviceName | select Load $sessions = $sessions -split('=') $load = $Sessions[1] $load=$load.Trim("}") if ($load -eq 0) {Stop-Computer $DeviceName $ServersinUse=Get-Content $SessionHostFile | Where-Object {$_ -ne $DeviceName} $ServersinUse | Out-File $SessionHostFile } }
#Wait on hour and check if there are (still) sessions running on the server #If there are no sessions shutdown the machine, else wait #--------------------------------- Clear-Variable DeviceName start-sleep -s 3600 $SessionHosts=Get-Content $SessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line $sessions=get-xaserverload -ServerName $DeviceName | select Load $sessions = $sessions -split('=') $load = $Sessions[1] $load=$load.Trim("}") if ($load -eq 0) {Stop-Computer $DeviceName $ServersinUse=Get-Content $SessionHostFile | Where-Object {$_ -ne $DeviceName} $ServersinUse | Out-File $SessionHostFile } } #Wait on hour and check if there are (still) sessions running on the server #If there are no sessions shutdown the machine, else wait #--------------------------------- Clear-Variable DeviceName start-sleep -s 3600 $SessionHosts=Get-Content $SessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line $sessions=get-xaserverload -ServerName $DeviceName | select Load $sessions = $sessions -split('=') $load = $Sessions[1] $load=$load.Trim("}") if ($load -eq 0) {Stop-Computer $DeviceName $ServersinUse=Get-Content $SessionHostFile | Where-Object {$_ -ne $DeviceName} $ServersinUse | Out-File $SessionHostFile } }
#Wait on hour and check if there are (still) sessions running on the server #If there are no sessions shutdown the machine, else wait #--------------------------------- clear-Variable DeviceName start-sleep -s 3600 $SessionHosts=Get-Content $SessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line $sessions=get-xaserverload -ServerName $DeviceName | select Load $sessions = $sessions -split('=') $load = $Sessions[1] $load=$load.Trim("}") if ($load -eq 0) {Stop-Computer $DeviceName $ServersinUse=Get-Content $SessionHostFile | Where-Object {$_ -ne $DeviceName} $ServersinUse | Out-File $SessionHostFile } }
#Wait on hour and check if there are (still) sessions running on the server #If there are no sessions shutdown the machine, else wait #--------------------------------- clear-Variable DeviceName start-sleep -s 3600 $SessionHosts=Get-Content $SessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line $sessions=get-xaserverload -ServerName $DeviceName | select Load $sessions = $sessions -split('=') $load = $Sessions[1] $load=$load.Trim("}") if ($load -eq 0) {Stop-Computer $DeviceName $ServersinUse=Get-Content $SessionHostFile | Where-Object {$_ -ne $DeviceName} $ServersinUse | Out-File $SessionHostFile } } #Wait on hour and check if there are (still) sessions running on the server #If there are no sessions shutdown the machine, else wait and send message to the users #--------------------------------- Clear-Variable DeviceName start-sleep -s 3600 $SessionHosts=Get-Content $SessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line $sessions=get-xaserverload -ServerName $DeviceName | select Load $sessions = $sessions -split('=') $load = $Sessions[1] $load=$load.Trim("}") if ($load -eq 0) {Stop-Computer $DeviceName $ServersinUse=Get-Content $SessionHostFile | Where-Object {$_ -ne $DeviceName} $ServersinUse | Out-File $SessionHostFile } else {& $exe * /Server:$DeviceName /time:120 "DThis server will be shut down in two hours. Please log-off. You can directly login again"} } #Wait on hour and check if there are (still) sessions running on the server #If there are no sessions shutdown the machine, else wait and send message to the users #--------------------------------- clear-Variable DeviceName start-sleep -s 3600 $SessionHosts=Get-Content $SessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line $sessions=get-xaserverload -ServerName $DeviceName | select Load $sessions = $sessions -split('=') $load = $Sessions[1] $load=$load.Trim("}") if ($load -eq 0) {Stop-Computer $DeviceName $ServersinUse=Get-Content $SessionHostFile | Where-Object {$_ -ne $DeviceName} $ServersinUse | Out-File $SessionHostFile } else {& $exe * /Server:$DeviceName /time:120 "This server will be shut down in one hour. Please log-off. You can directly login again"} } #Wait on hour and check if there are (still) sessions running on the server #If there are no sessions shut down the machine, else wait 5 minutes and shut down the servers #--------------------------------- Clear-Variable DeviceName #start-sleep -s 3600 $SessionHosts=Get-Content $SessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line $sessions=get-xaserverload -ServerName $DeviceName | select Load $sessions = $sessions -split('=') $load = $Sessions[1] $load=$load.Trim("}") if ($load -eq 0) {Stop-Computer $DeviceName $ServersinUse=Get-Content $SessionHostFile | Where-Object {$_ -ne $DeviceName} $ServersinUse | Out-File $SessionHostFile } else {& $exe * /Server:$DeviceName /time:120 "This server will be shut down within five minutes. Please log-off. You can directly login again" start-sleep 300 Stop-Computer $DeviceName -Force } } |
Script 3: Place Sessions Host in maintenance and shutdown
When the hypervisor administrator finished his maintenance activities the XenApp Session Host can be put back in production. Also this part is divided in two parts. The first part is script 3 in which the Worker Group settings are restored and the machine is taken out of maintenance mode. This is based on the file from script 2 configured at the variable $ServertoWorkerGroup. Therefore please check that the variable in this script points to the same location as in script two.
The script will read this file (which now includes the Reboot Worker Group the machine was member of) and adds the machine to his original Worker Group. Also the machine is removed from the reboot Worker Group, so the XenApp administrators know that the server will be back in production again.
#--------------------------------------------------------------------- # Script: EndSessionHostMainteance.ps1 # Take XenApp Session Hosts online after ESX maintenance # Creator: Wilco van Bragt # Creation Date: 10-10-2014 #--------------------------------------------------------------------- # Version: 0.1 # By: Wilco van Bragt # Date: 10-10-2014 # Changes: Initial release #--------------------------------------------------------------------- # Textfile with XenApp Session Hosts is required (generated by SessionHostMaintenance Script) # Requirements: # - Scripts needs to run on server with Citrix PowerShell cmdlets #--------------------------------------------------------------------- # Import Modules #--------------------------------- add-pssnapin Citrix.* #Define Variables #--------------------------------- $MaintenanceWG="Maintenance" $ServertoWorkerGroup="c:\Temp\ServertoWorkerGroup.txt" #Read Session Hosts names, remove server from maintenace WG and add to original Reboot WG #--------------------------------- $SessionHosts=Get-Content $ServertoWorkerGroup foreach ($line in $SessionHosts) { $line = $line -split(',') $DeviceName = $Line[0] write-host "$DeviceName" $WG = $Line[1] write-host "$WG" add-xaworkergroupserver $WG $DeviceName remove-xaworkergroupserver $MaintenanceWG $DeviceName Set-XAServerLogOnMode -LogOnMode AllowLogOns -ServerName $DeviceName } Remove-Item $ServertoWorkerGroup -Force |
Script 4: Place Sessions Host in maintenance and shutdown
The last script is pretty simple. The last step is to start the virtual machines again on the hypervisor. This can be done in script 3 as well, but to really divide the steps I created a separate script. The script will ask the location of the original file created in script one. The file will be read and for each machine the start-vm command will be provided to start the machine again.
#--------------------------------------------------------------------- # Script: StartXenAppSessionHosts.ps1 # Start XenApp Session Hosts after maintenance # Creator: Wilco van Bragt # Creation Date: 15-10-2014 #--------------------------------------------------------------------- # Version: 0.1 # By: Wilco van Bragt # Date: 15-10-2014 # Changes: Initial release #--------------------------------------------------------------------- # # Requirements: # - Scripts needs to run on server with VMware ESX PowerShell cmdlets # - File with XenApp Session Hosts created by GetXenAppSessionHosts.ps1 #--------------------------------------------------------------------- # Import Modules #--------------------------------- Add-PSSnapin VMware.VimAutomation.Core # Provide file to store XenApp Session Hosts #--------------------------------- $XenAppSessionHostFile=Read-Host "Please enter the filename and path which contains the XenApp Session Hosts" # Read Session Host XenApp Session Hosts #--------------------------------- $SessionHosts=Get-Content $XenAppSessionHostFile foreach ($line in $SessionHosts) { $DeviceName = $Line start-vm $DeviceName |
In this article I provided and explained four scripts, which are used to arrange that maintenance tasks can be executed on the hypervisor platform. It shows that lots of stuff can be easily automated in small and simple scripts. Use them for your needs.