PowerShell: Friday Script Blitz



In my current position I’m getting to do a lot of PowerShell scripting. Typically these are quick scripts for maintenance or finding information about our Citrix environment. I’m posting several here to share.

NOTE: These scripts were written against a XenApp 6.5 environment.


Lists active published applications’ command lines and working directories based on a search word.


Get it from GitHub.


Lists active published applications from a designated XA 6.x Worker Group


Get it from GitHub


Displays total, active, and disconnected sessions from a XA 6.x farm


Get it from GitHub

Happy Friday!

PowerShell: Drain users from a XenApp Server



Citrix has provided XenApp administrators several tools to control server access. Applying load evaluators and login modes allows us to establish reboot and maintenance schedules. At times, however getting users off a server becomes urgent. In this post we’ll cover a script designed to automatically drain users off a XenApp server with different levels of “aggression”.


Your ever-intrepid security team informs you that a user on one of your Citrix servers went to a malicious web site. While everyone is reasonably sure that the web security filters prevented anything bad from happening, you err on the side of caution and implement a standard procedure to remove the system from production, perform a security scan, get the connected users off, and reboot the server (because you’ve naturally implemented PVS and rebooting will remove any changes that have occurred since the image was last sealed). Depending on your idle and disconnection policies, this could take a while. If only there was a way to get users off a system in a timely manner without inconveniencing them too much. Oh wait…PowerShell

Why So Aggressive?

The purpose of the drain-xaserver script is to look for disconnected ICA sessions and log them off your server. But what if your users are busy working away or if you have liberal idle session timeouts? Well, in order to add some urgency to this script, I included a switch parameter that determines how long a session can be idle before it is disconnected and then logged off.

#Set Aggression level
if ($aggression -eq "Red") {
$timeOut = 15
write-verbose "Agression level is Red. Idle session timeout set to 15 minutes"
} elseif ($aggression -eq "Yellow") {
$timeOut = 30
write-verbose "Agression level is Yellow. Idle session timeout set to 30 minutes"
} else {
$timeOut = 0
write-verbose "Agression level is Green. Idle session timeout is default"

If you choose Green (the default value), then your normal idle timeouts will occur. If you choose Yellow, the idle timeout gets reduced to 30 minutes. If you choose Red, the idle timeout is further reduced to 15 minutes. You can, of course, modify these settings to be longer or shorter. Just to be clear, these settings will override your Farm-wide idle session timeouts on the server you run this script against only while the script is running.

# Get the assigned Logon Mode
$xaLogonMode = $isServer.LogOnMode.ToString()
if ($xaLogonMode -eq "ProhibitNewLogOnsUntilRestart") {
Write-Verbose "Server set to ProhibitNewLogOnsUntilRestart"
$canDrain = $true
} elseif ($xaLogonMode -eq "ProhibitNewLogOns") {
Write-Verbose "Server set to ProhibitNewLogOns"
$canDrain = $true
} elseif ($xaLogonMode -eq "ProhibitLogOns") {
Write-Verbose "Server set to ProhibitLogOns"
$canDrain = $true
} else {
Write-Verbose "Server set to AllowLogOns"
$canDrain = $false

This script checks that a compatible Logon Mode was assigned to the server before sessions get logged off. In this case, the following Logon Modes will allow the script to proceed:

  • ProhibitLogOns
  • ProhibitNewLogOns
  • ProhibitNewLogOnsUntilRestart

Otherwise, the script will not run.

While True…Do Stuff

while ($sessCount -ge 0) {
$xaSessions = (Get-XASession ComputerName $XMLBroker ServerName $XenAppServerName full | where {($_.State -eq 'Active' -or $_.State -eq 'Disconnected') -and $_.Protocol -eq 'Ica'} | select SessionId,accountname,state,lastinputtime Unique)
$sessCount = ($xaSessions | measure).count
$curTime = (get-date Format T)
write-host "Current time is: $curTime"
Write-Host "Current session Count = $sessCount on $XenAppServerName" ForegroundColor White
if ($sessCount -eq 0) {
Write-Host "$XenAppServerName is free of users (ICA Sessions)" ForegroundColor White
Exit 0
} else {
$disconnected = @()
Write-Host "Checking for disconnected and idle users on $XenAppServername" ForegroundColor White
$disconnected = $xaSessions | Where-Object {$_.State -eq 'Disconnected'}
$active = $xaSessions | Where-Object {$_.State -eq 'Active'}
if ($timeout -ne 0) { # Check if aggression is not Green, otherwise don't look at Active sessions
foreach ($idleuser in $active) {
$idleusertime = (New-TimeSpan Start (get-date) End $idleuser.LastInputTime).negate().Minutes + ((New-TimeSpan Start (get-date) End $idleuser.LastInputTime).negate().hours * 60)
if ($idleusertime -gt $timeOut) {
$user = $idleuser.accountname.Tostring()
write-verbose "$user has been idle for $idleusertime minutes. They will be disconnected."
[array]$disconnected += $idleuser
$xaSessions = (Get-XASession ComputerName $XMLBroker ServerName $XenAppServerName full | where {($_.State -eq 'Active' -or $_.State -eq 'Disconnected') -and $_.Protocol -eq 'Ica'} | select SessionId,accountname,state,lastinputtime Unique)
$sessCount = ($xaSessions | measure).count
if ($disconnected -eq $null) {
Write-Host "There are no disconnected sessions on $XenAppServerName" ForegroundColor White
Write-Host "Waiting 10 minutes" ForegroundColor Red
Start-Sleep Seconds 600
} else {
Write-host "Logging off" ($disconnected | measure).count "disconnected users from $XenAppServerName" ForegroundColor White
foreach ($user in $disconnected) {
$namedUser = $user.AccountName
write-host "Logging off $namedUser" ForegroundColor White
Stop-XASession ComputerName $XMLBroker ServerName $XenAppServerName SessionId $user.SessionId
$xaSessions = (Get-XASession ComputerName $XMLBroker ServerName $XenAppServerName full | where {($_.State -eq 'Active' -or $_.State -eq 'Disconnected') -and $_.Protocol -eq 'Ica'} | select SessionId,accountname,state,lastinputtime Unique)
$sessCount = ($xaSessions | measure).count

The script checks the number of ICA sessions and as long as it isn’t zero, keeps checking every 10 minutes (adjust for your environment) for new disconnected sessions. If you have set a Red or Yellow aggression level, line 15 (above) shows how the script calculates the user’s idle time. The LastInputTime value comes from running Get-XASession with the “-full” switch. This queries Citrix for session details that are usually omitted when using Get-XASession.

The Script

I went through a lot of revisions while testing, so please let me know if you run into any issues using this script in a XenApp 6.x environment. You can get the script from GitHub.

Thanks for reading,

PowerShell: Copying Published Applications Between 7.x Farms



We are in the midst of migrating to a XenApp 7.9 environment from a 6.5 environment. There are many pain points associated with this sort of transition:

  1. Lack of Worker Groups (similar functionality returns in XenApp 7.12)
  2. Organizing your existing application deployment around Machine and Delivery groups
  3. Revisiting every published application in relation to user access and how Delivery groups are leveraged
  4. Recreating all your published applications

In my current 6.5 environment we have over 240 published applications. Recreating these in the new 7.9 farm is nightmarish. Luckily, Shaun Ritchie (from EUC Consulting) has provided the Citrix community a great script that migrates (with icons and user accounts) XenApp 6.5 published applications to a XenApp 7.x farm. You can see the script on his blog post “XenApp 6.x to XenApp 7.x App Migration Script“.

This script does a lot of heavy lifting and makes a migration much easier. What do you do if you have multiple 7.x farms? I thought it would be trivial to copy the newly migrated 6.5 applications from one 7.x farm to another, but this was not the case. I used Shaun’s script as a base and re-worked it to allow the copying of apps from one XenApp 7.x farm to another.

The Script

You can get the script from GitHub

Thanks for reading,
Alain Assaf