Intro
For years, management of Citrix Published Applications has been pretty heavy-handed. You had the following options:
- You had enough servers to ensure your users always had access to their apps.
- You established a regular maintenance period that everyone knew about (I’m trying not to burst out laughing) that allowed you to perform application and server maintenance.
- You implemented an application virtualization technology that allowed for incremental testing and roll-out of application changes without affecting all your users.
- You used the Citrix console to disable and hide an application (resulting in calls to the help desk like the above picture).
In this blog post, I’ll present a PowerShell script that allows you to display a maintenance message instead of hiding the application. This allows you to do maintenance and give users some feedback about what’s going on.
Disabling the application
We’re assuming the runner of the script has XenApp farm admin permissions enough to change published application properties and that the XenApp 6.5 SDK is installed. When the change-appmaintenance.ps1 script runs, it creates a text file with the same name as the published app under C:\_scripts\appmaintenance
that stores 3 items of information (this assumes the –disabled
flag is used):
- The original Command Line field of the published application (used when we need to put the application back in production.
- The person who ran the script.
- The current date and time (when the script was run).
Here’s a command line example (the –verbose flag is optional, but shows feedback messages):
PS C:\_scripts> .\change-appmaintenance.ps1 -PublishedApp "testdisable" -disable -Verbose
Here is the maintenance file created for the TestDisable published application.
Once the information is saved, the script changes the command line to the following:
The show-appmaintenancebox.ps1 script is simple, but you can add more information as needed. You could further customize the maintenance message by passing parameters, but you may run into the character limit (256 characters) in the Command Line field. In this case you will get the following message:
You could also solve the above issue by calling a batch file to run the script.
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("This application is unavailable because it is undergoing maintenance. Please try again later.",0,"APPLICAITON UNDER MAINTENANCE",0)
NOTE: More info about the Popup Method is here
When a user launches the application, the script now displays this window.
Enabling the Application
To reverse the changes you run the same command without the –Disabled flag (the –verbose flag is optional, but shows feedback messages):
PS C:\_scripts> .\change-appmaintenance.ps1 -PublishedApp "testdisable" –Verbose
The script will check for the published application maintenance file under C:_scripts\appmaintenance, read the file, and use the first line to change the Command Line back to the correct one for the application. Then it will delete the maintenance file.
The Script
<#
.SYNOPSIS
Disables (or re-enables) a published application by replacing the original command line with one that
calls a pop-up window.
.DESCRIPTION
Disables (or re-enables) a published application by replacing the original command line with one that
calls a pop-up window.
It is recommended that this script be run as an a XenApp Farm administrator.
This script assumes that the XenApp 6.5 powershell commandets are installed.
.PARAMETER PublishedApp
Required parameter. Application that will be enabled or disabled.
.PARAMETER Disable
Conditional parameter.
If present, the application is disabled and maintenance message will be displayed. If not, then the maintenance message
is removed and applicaiton is republished.
.EXAMPLE
PS C:\PSScript > .\change-appmaintenance.ps1 -PublishedApp $PublishedApplicationName
Script will try and re-enable the application.
Will not display feedback
.EXAMPLE
PS C:\PSScript > .\change-appmaintenance.ps1 -PublishedApp $PublishedApplicationName -verbose
Script will try and re-enable the application.
Will display feedback
.EXAMPLE
PS C:\PSScript > .\change-appmaintenance.ps1 -PublishedApp $PublishedApplicationName -Disabled -verbose
Script will disable the application.
Will display feedback
.INPUTS
PublishedApp maintenance file. If the file exists it assumes that the application was already put in maintenance. The script will read in the
information from the file and take it out of maintenance (assuming the disabled flag is not present). It will delete the existing file if
taking the application is taken out of maintenance.
.OUTPUTS
A maintenance file will be generated per application (assuming the disabled switch is present). The file will contain the original location of the application from the published application
properties, the name of the script runner, and the date the change was made.
.NOTES
NAME: change-appmaintenance.ps1
VERSION: 1.00
CHANGE LOG - Version - When - What - Who
1.00 - 08/15/2014 - Inititail script - Alain Assaf
AUTHOR: Alain Assaf
LASTEDIT: August 15, 2014
.LINK
http://www.linkedin.com/in/alainassaf/
http://wagthereal.com
http://gallery.technet.microsoft.com/scriptcenter/PowerShell-Message-Box-6c6e4f75
#>
Param(
[parameter(Position = 0, Mandatory=$true )]
[ValidateNotNullOrEmpty()]
[string]$PublishedApp,
[parameter(Position = 1, Mandatory=$False )]
[ValidateNotNullOrEmpty()]
[switch]$Disable)
### FUNCTION: get-mysnapin ####################################################
Function Get-MySnapin {
Param([string]$name)
if(-not(Get-PSSnapin -name $name)) {
if(Get-PSSnapin -Registered | Where-Object { $_.name -eq $name }) {
add-PSSnapin -Name $name
$true
} #end if module available then import
else { $false } #snapin not available
} # end if not snapin
else { $true } #snapin already loaded
}
### FUNCTION: get-mysnapin ####################################################
#Constants
$datetime = get-date -format "MM-dd-yyyy_HH-mm"
$Domain=(Get-WmiObject Win32_ComputerSystem).Domain
$ScriptRunner = (get-aduser $env:username | select name).name
$XAZDC = "XenApp65ZDC.local"
$appmaintfolder = "C:\_scripts\appmaintenance"
$PSSnapins = ("Citrix.XenApp.Commands")
$XApps = New-Object System.Collections.ArrayList
#Populate XApps
foreach ($a in $PublishedApp) {$XApps.Add($a)>$null}
#Import Snapin(s)
foreach ($snapin in $PSSnapins) {
if (!(get-MySnapin $snapin)) {
write-verbose "$snapin PowerShell Cmdlet not available."
write-verbose "Please run this script from a system with the $snapin PowerShell Cmdlets installed."
exit
}
}
#Confirm application(s) exists
foreach ($apps in $XApps) {
$appresult = Get-XAApplication -ComputerName $XAZDC -BrowserName $apps -ErrorAction SilentlyContinue
if ([boolean]($appresult)) {
write-verbose "$apps exists"
if ($Disable) { #Disable flag is present
$appmaintfile = $apps + ".txt"
if (test-path -Path $appmaintfolder\$appmaintfile) {
write-verbose "$appmaintfile already exists. Please confirm application name. No changes made"
} else { #Create maintenance file and replace app's command line
add-content -Value $appresult.CommandLineExecutable -Path $appmaintfolder\$appmaintfile
Add-Content -Value $ScriptRunner -Path $appmaintfolder\$appmaintfile
Add-Content -Value $datetime -Path $appmaintfolder\$appmaintfile
Set-XAApplication -computername $XAZDC -BrowserName $apps -CommandLineExecutable "powershell.exe -noprofile -executionpolicy bypass -command c:\_scripts\Show-appmaintenancebox.ps1"
}
} else { #Read maintenance file and restore app's command line
$appmaintfile = $apps + ".txt"
if (test-path -Path $appmaintfolder\$appmaintfile) {
$fileinfo = get-content -path $appmaintfolder\$appmaintfile
Set-XAApplication -computername $XAZDC -BrowserName $apps -CommandLineExecutable $fileinfo[0]
remove-item -Path .\appmaintenance\$appmaintfile
Write-Verbose "Application maintenance removed for $apps"
} else {
write-verbose "*** ERROR *** expected maintenance file:$appmaintfile is missing. Please confirm application name. Script will exit"
exit
}
}
} else {
Write-Verbose "$apps does not exist"
}
}
Script Logic Flow
Future tasks
To use this with your users, I would recommend that you try calling the PowerShell script with VBS. This should allow you to hide the PowerShell window that calls the script. You can read more here: Hiding a Powershell window using VBscript
I hope you found this script useful and that it may help you. I welcome all comments and suggestions.
Value for Value
If you received any value from reading this post, please help by becoming a supporter.
Thanks for reading,
Alain