Wednesday 6 July 2011

Creating a Server Monitoring Graph in XenApp 6.0 and 6.5

Knowing what is going on in your Citrix farm is always difficult when there are more than a few users and servers involved.  Edgesight is very useful for this in XenApp, but it does lack a decent Dashboard function so you can tell at a glance what the load is like on your servers.

In previous versions of Citrix I’ve seen people write applications which use MFCOM to find out how many sessions are on each server and write them out to a nice graph – you can then see at a glance whether for instance everyone is on one server, or if a server appears to have rebooted or been left disabled.

Citrix Server Graph

 

The way I do this currently is using a PowerShell script, running as a scheduled task.  This then creates image files which I can display in a webpage.

In this earlier article I showed how you could download and install the Citrix components into PowerShell and use it to control the farm.  Its worth doing this, and also using the PowerShell ISE Editor to write your PowerShell scripts.

You should also download something that will let you create graphs from PowerShell.  An easy and free way of doing this is the MS Chart Controls for .NET 3.5 download.  You can download this from here:
http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=14422

The first step is to use Powershell to get a list of the server names that you are interested in, and a list of the active sessions on the farm.  Install the XenApp Powershell SDK from here and run the following from a farm serer. The first line is required to load the Citrix add-ons you just installed to PowerShell:

Add-PSSnapin Citrix*
$filter = 'xen'
$servernames = Get-XAServer | where-object {$_.ServerName -match $filter} | select-object ServerName
$sessionsactive = Get-XASession -Farm | where-object {$_.State -eq "Active" -and $_.ServerName -match $filter}

The value of $filter can be edited to filter on server name – only server names including that string will be measured.  If you set it to just be ‘’, all servers will be used.

This should give you a pair of arrays, $Servernames and $sessionsactive, containing all the names and session details.  Now we can iterate through the server names, finding out the number of active sessions for each on and writing it to another array, then finally sorting that array into alphabetical order by server name:

$servercounts = @{}
foreach ($servername in $servernames)
{
    $countActive = @($sessionsactive | where-object {$_.ServerName -eq $servername.ServerName }| Select-Object SessionId -unique)           
    $servercounts.add($servername.ServerName, $countActive.Count)
}
$servercounts = $servercounts.GetEnumerator() | sort Name

You now have an array called $servercounts.  If you ran it and exported its contents it would look something like this:                      

Name      Value                                                           
----      -----
XEN01     28
XEN02     30
XEN03     31
XEN04     28
XEN05     28
XEN06     29
XEN07     28
XEN08     29
XEN09     27

Finally, time to generate the chart, if that is what you want.  To use the MS Chart Controls (which will need to be installed on the XenApp server too) add these lines to the top of the script:

[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")

Then add these lines to the end of the script to create the graph and save it to the c: drive as a PNG file.  Note the lines to create a title for it as well, so you know whether the image is out of date:

# create chart object
$Chart = New-object System.Windows.Forms.DataVisualization.Charting.Chart
$Chart.Width = 900
$Chart.Height = 330
$Chart.Left = 10
$Chart.Top = 10

# create a chartarea to draw on and add to chart
$ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$Chart.ChartAreas.Add($ChartArea)
[void]$Chart.Series.Add("Data")
foreach ($server in $servercounts)
{
    $dp1 = new-object System.Windows.Forms.DataVisualization.Charting.DataPoint(0, $server.Value)
    $dp1.AxisLabel = $server.Name
    $Chart.Series["Data"].Points.Add($dp1)
}

$title = new-object System.Windows.Forms.DataVisualization.Charting.Title
$Chart.Titles.Add( $title )
$Chart.Titles[0].Text = date

$Chart.SaveImage("c:\Graph\XenAppFarm.png","png")

The script is best being signed (or remove the need for signing in PowerShell scripts) and then needs to be scheduled.  I do this with a scheduled task on a XenApp server, which calls a batch file with contents of:

call powershell -command "& {C:\Graph\Generate.ps1}"

Finally you need a way of viewing the image – I just use a HTML file with an automated refresh, such as this:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>XenApp Farm</title>
    <meta http-equiv="refresh" content="60">
</head>
<body>
    <img src="c:\Graph\XenAppFarm.png">       
</body>
</html>

Just to recap, here’s the whole sample script:

# load the appropriate assemblies
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")
Add-PSSnapin Citrix*

# get the server names and sessions
$filter = ''
$servernames = Get-XAServer | where-object {$_.ServerName -match $filter} | select-object ServerName
$sessionsactive = Get-XASession -Farm | where-object {$_.State -eq "Active" -and $_.ServerName -match $filter}

$servercounts = @{}

# count active sessions for each server name
foreach ($servername in $servernames)
{
    $countActive = @($sessionsactive | where-object {$_.ServerName -eq $servername.ServerName }| Select-Object SessionId -unique)           
    $servercounts.add($servername.ServerName, $countActive.Count)
}
$servercounts = $servercounts.GetEnumerator() | sort Name

# create chart object
$Chart = New-object System.Windows.Forms.DataVisualization.Charting.Chart
$Chart.Width = 900
$Chart.Height = 330
$Chart.Left = 10
$Chart.Top = 10

# create a chartarea to draw on and add to chart
$ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$Chart.ChartAreas.Add($ChartArea)
[void]$Chart.Series.Add("Data")

# add a data point for each server
foreach ($server in $servercounts)
{
    $dp1 = new-object System.Windows.Forms.DataVisualization.Charting.DataPoint(0, $server.Value)
    $dp1.AxisLabel = $server.Name
    $Chart.Series["Data"].Points.Add($dp1)
}
# set the title to the date and time
$title = new-object System.Windows.Forms.DataVisualization.Charting.Title
$Chart.Titles.Add( $title )
$Chart.Titles[0].Text = date

# save the chart to a file
$Chart.SaveImage("c:\Graph\XenAppFarm.png","png")

Resources used to write the above include:

http://blogs.technet.com/b/richard_macdonald/archive/2009/04/28/3231887.aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.seriescharttype.aspx

3 comments:

-Jace said...

You should look at Zenoss. I do basically the same thing, but I use my powershell to write a txt file that my monitoring system picks up and graphs with RRD. If I could attach something I would show you what mine looks like. Plus zenoss fits into an overall network management strategy.

-Jace Jenkins

FD said...

Great article. I would just add a couple of changes:

Add-PSSnapin Citrix* -ErrorAction SilentlyContinue

This removes the error messages if you have already loded the snapins...

$Chart.ChartAreas[0].AxisX.LabelStyle.Angle = -45
$Chart.ChartAreas[0].AxisX.Interval = 1

These two lines just before the foreach loop make the legend word better if you have more than 10 server (otherwise the graph scales and you will read one name every ten).

Regards,

Francesco Dipietromaria
http://www.dpmworld.net

Woter said...

Awsome. Just what I was looking for. I've slightly changed the script so it runs on non-XA servers but with the SDK installed. It connects to our data collector:

$ErrorActionPreference = "SilentlyContinue"

Add-PSSnapin Citrix*

$filter = "SOMESERVER*"
$sServerZDC = "DataCollector"

$oFarm = Get-XAFarm -ComputerName $sServerZDC
$oServers = Get-XAServer -ComputerName $sServerZDC | Where-Object {$_.ServerName -like $filter}

$servercounts = @{}
foreach ($servername in $oServers)
{
$sessionsactive = Get-XASession -Farm -ComputerName $servername | where-object {$_.State -eq "Active" }
$countActive = @($sessionsactive | where-object {$_.ServerName -eq $servername.ServerName }| Select-Object SessionId -unique)
$servercounts.add($servername.ServerName, $countActive.Count)
}
$servercounts = $servercounts.GetEnumerator() | sort Name

#echo $servercounts

Some of servers are listed in the farm, but don't actually exist. As a result it can take a while to generate the chart as it has to timeout on each non-existent server. Maybe someone known a way to reduce the timeout.

Post a Comment