Tuesday, June 26, 2012

Presence Information from Citrix Sessions

I was investigating a quick method of getting user presence information for our contact centre to see who is available in the business.  We do not have any unified communications tools as yet (hopefully we may get lync at some point though!) and I thought there must be a quick way of achieving this.

My intial thought was creating a internal web server which acted like FourSquare, users could check in and out.  The problem is that it is useless if people do not use it.

I then thought that nearly all of this information is already available through the Delivery Services Console in XenApp (app center, presentation server console, citrix management console.....or whatever it will be called next!!).  You can browse for sessions and see who is logged in and who is idle.

The vast majority of people (over 90% of our users) login to the same published desktop which means 1 script will produce decent results.

I created a service account which was a custom administrator to the Citrix farm.  This would be used to get information using the Citrix XenApp Powershell cmdlets.

Initial Code

I decided to use the XenApp Powershell cmdlet Get-XAsession to get me this information.  This only produces a subset of data normally, but providing Get-XAsession -Full switch gives you all the data.  Running this against lots of sessions can be slow.

This -Full switch provides last input time.  This can be used to calculate if the user session is idle.  This can be incorporated into a script which checks if the users is online, offline or sessions over 5 minutes idle being classed as away from their desk.


The next step was deciding the output of the data, I wanted to store everything in either a hashtable and then output to HTML, or dynamically write to HTML.  I found that doing this for 600+ sessions was far too slow and eventually made the status message incorrect.  If the query took 4 minutes, then idle users may not be idle any longer.

I then decided to cut down the script based on user input.  The user can enter a name, it can then be checked in the farm and produce 1 result.  Much quicker but more code involved.

This can be done in native powershell using read-host and write-host but I want something a little better on the eye.  2 options were open, HTA window or Windows Forms. 


HTA windows are HTML windows which can run vbscript or javascript to launch powershell.  When you build a fresh Windows 2003 server, a HTA window appears asking what you want to do next!  They are limited because passing data between the HTA window and the powershell requires output to clipboard or external file.  I dabbled in this but found the process quite buggy for my script.

Windows forms are .Net based and can easily incorporate input and output into powershell windows.  This is the way I decided to go.

Below is screenshot of the main screens.  The first screen is what greets users initially.

When typing in a username and pressing OK, the powershell cmdlets for Citrix and Quest AD tools are loaded, the text is passed to get-QADuser.  If nothing can be found by get-QADuser some text is passed back to the user.

If get-QADuser finds something, the first account is picked up and passed into Get-XAsession.  If nothing is found by Get-XAsession for this user, a message is posted stating the user is not online.

If a user session is found by Get-XAsession a calculation is done to work out the idle time, if it is less than 5 minutes a message is provided stating the user is online.

If the calculation works out the users has been idle for more than 5 minutes an away message is posted.  It will state the amount of minutes they have been away for as well.

Here is the powershell code I have used.

[system.reflection.assembly]::LoadWithPartialName( "System.Windows.Forms")

$form = New-Object Windows.Forms.Form

#window title
$form.text = "Presence"

#text label for user instruction
$label = New-Object Windows.Forms.Label
$label.Location = New-Object Drawing.Point 50,30
$label.Size = New-Object Drawing.Point 200,15
$label.text = "Enter the users name below"

#label used for output of script
$statuslabel = New-Object Windows.Forms.Label
$statuslabel.Location = New-Object Drawing.Point 35,125
$statuslabel.Size = New-Object Drawing.Point 300,15
$statuslabel.visible = $False

#textfield used to collect name from user
$textfield = New-Object Windows.Forms.TextBox
$textfield.Location = New-Object Drawing.Point 50,60
$textfield.Size = New-Object Drawing.Point 200,30

#go button to execute the script
$button = New-Object Windows.Forms.Button
$button.text = "Go!"
$button.Location = New-Object Drawing.Point 100,90
$statuslabel.visible = $False

if ( (Get-PSSnapin -Name Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue) -eq $null )
{Add-PsSnapin Quest.ActiveRoles.ADManagement}

if ( (Get-PSSnapin -Name Citrix* -ErrorAction SilentlyContinue) -eq $null )
{Add-PsSnapin Citrix*}

$accounts = @(get-qaduser $textfield.text)
$passedname = $textfield.text
If(!$accounts) {$Statuslabel.text = "$passedname cannot be found in the system"
   $statuslabel.visible = $True}

$account = $accounts[0]
$session = Get-XASession -Account $account.ntaccountname -Full | Where {$_.State -ne "Disconnected" -and $_.BrowserName -eq "My Desktop"} | sort-object AccountName
$fullname = $account.name
If(!$session) {$Statuslabel.text = "$fullname is not online"
   $statuslabel.visible = $True}

$lastinput = $session.LastInputTime
$currenttime =$session.CurrentTime
$idletime =($currenttime - $lastinput).Minutes

if ($idletime -lt 5) {$Status = "Online"
$Statuslabel.text = "$Fullname is $status"
    $statuslabel.visible = $True}
Elseif ($idletime -gt 4) {$Status = "Away"
$Statuslabel.text = "$Fullname has been $status for $idletime minutes"}
    $statuslabel.visible = $True




Next Steps

I am looking at making the GUI look a bit nicer and adding other information such as location based on client IP address.  I am also looking at better ways of inputing names, maybe a dropdown list.  This could help trying to identify people with the same name.

I am not a powershell expert, so the code above may not be 100% optimal, feel free to suggest improvements or ask questions.



Post a Comment