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.

Output

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. 

GUI

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")
[system.reflection.assembly]::LoadWithPartialName("System.Drawing")


$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
$button.Add_Click({
$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}

If($accounts){
$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}

If($session){
$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

  }
}
})

$form.controls.add($button)
$form.controls.add($label)
$form.controls.add($StatusLabel)
$form.controls.add($textfield)


$form.ShowDialog()


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.

Thanks
Sam





Wednesday, June 20, 2012

Wyse ThinOS 7.1 session disconnecting

We utilise Wyse ThinOS terminals for users at my organisation.  They connect to a full published desktop based on XenApp 6.  The Wyse terminals have been really useful as they load very quickly and configuration is easy using INI file and DHCP flags.  This means we can ship a new unit out to site with zero configuration.  True plug and play in action!!!

We have started to purchase some newer terminals recently including the R10 and T10.  The R10 is a little older and originally came with 7.0 firmware.  The T10 is a newer terminal which is the replacement for C10 and S10 terminals.  It has a small form factor and can handle multi monitors very well indeed.

The T10 ships with firmware version 7.1.  We have found this to be very problematic in our environment.  Users would start their desktops and get disconnected at random points in the day.  We downgraded any R10s with 7.1 firmware back 7.0 and it fixed the issue.  Unfortunately you cannot downgrade the T10!!

To reproduce this problem I would watch the following video file from Gizmodo

http://gizmodo.com/5743871/the-most-beautiful-short-film-about-cryptography-youll-see-today

After about 30-60 seconds the session would disconnect.  Our terminals are configured to shutdown on session end, which means the user would have to boot the terminal again. 

If the terminal is not configured for auto shutdown the following error would appear in the system information tab.

ICA: read error 0 from ica_frame_recv

We opened a support case with Wyse and they informed us that this issue had something to do with session reliability.  To workaround the issue you can disable session reliability in the wnos.ini file

CONNECT=ICA \
BrowserIP=Server1,Server2 \
Application="AppName" \
Description="AppDesc" \
Icon=icon.JPG \
AutoConnect=Yes \
Username=$UN \
Password=$PW \
Domainname=domain \
Encryption=128 \
Resolution=DDC \
Fullscreen=yes \
HTTPBrowsing=yes \
SessionReliability=no \
Mapdisks=yes \
MapdisksUnderZ=yes \
LowBand=no \
UniSession=yes \
LocalCopy=no

This had an immediate impact.  The testing showed no disconnects, but we like session reliability.  If a network link goes down for 10 seconds we do not want all users being disconnected!

Wyse have provided me with a limited release hotfix (7.1._126.01) which resolves the issues without needing to turn off session reliability.  This will be included in WTOS 08 which is due for release in Q4 2012.

Thanks
Sam