
I have written a Python script to get some Citrix performance data and use it to create graph with Grafana. The result looks like this :

The Python script uses the linux wmic client you can find here
The software requirements are the following :
- a debian / ubuntu system (you can choose another os but prefer those ones if you need help :))
- influxdb database
- grafana
- python (for me I have the version 2.7.3)
- InfluxDBClient for python
- wmic tool
For the moment, there are two Python script : one to get Citrix site info like number of Active/Disconnected sessions and one for performance info (user latency, session bandwidth,…)
In this example, you will have to create two influxdb databases called ctxmon and ctxusr
Here we go…
[config] FORESTNAME=domain.local WMIC=/usr/bin/wmic WMIUSR=wmiusername WMIPWD=wmipassword CDCSRV=10.11.0.1 DBSRVIP=10.11.0.2 DBSRVUSR=dbusr DBSRVPWD=dbpwd DB_USR_NAME=ctxusr WMICLASS=Win32_PerfFormattedData_CitrixICA_ICASession WMIOBJECT=InputClipboardBandwidt,InputDriveBandwidth,InputPrinterBandwidth,InputSessionBandwidth,InputSessionCompression,InputSessionLineSpeed,LatencyLastRecorded,LatencySessionAverage,LatencySessionDeviation,OutputPrinterBandwidth,OutputSeamlessBandwidth,OutputSessionBandwidth,OutputSessionCompression,OutputSessionLineSpeed,OutputThinWireBandwidth WMINAMESPACE=Root/CIMV2
#!/usr/bin/python
from __future__ import division
import socket
import ConfigParser
import os
import subprocess
import threading
import re
import time
from influxdb import InfluxDBClient
config = ConfigParser.RawConfigParser()
config.read(os.path.dirname(os.path.realpath(__file__))+'/configusr.ini')
forestname = config.get('config', 'FORESTNAME')
wmic = config.get('config', 'WMIC')
wmiusr = config.get('config', 'WMIUSR')
wmipwd = config.get('config', 'WMIPWD')
cdcsrv = config.get('config', 'CDCSRV')
dbsrvip = config.get('config', 'DBSRVIP')
dbsrvusr = config.get('config', 'DBSRVUSR')
dbsrvpwd = config.get('config', 'DBSRVPWD')
db_usr_name = config.get('config', 'DB_USR_NAME')
wmiclass = config.get('config', 'WMICLASS')
wmiobject = config.get('config', 'WMIOBJECT')
wminamespace_ini = config.get('config', 'WMINAMESPACE')
sct = re.compile("^mon---", re.IGNORECASE)
client = InfluxDBClient(dbsrvip, 8096, dbsrvusr, dbsrvpwd, db_usr_name)
monsct = filter(sct.search, config.sections())
threadLimiter = threading.BoundedSemaphore(value=200)
class myThread (threading.Thread):
def __init__(self, threadID, name, ctxuser, wmicmd, wmimoninfo):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.ctxuser = ctxuser
self.wmicmd = wmicmd
self.wmimoninfo = wmimoninfo
def run(self):
threadLimiter.acquire()
try:
print_adrepl(self.name, self.ctxuser, self.wmicmd, self.wmimoninfo )
finally:
threadLimiter.release()
def print_adrepl(threadName, ctxuser, wmicmd, wmimoninfo):
json_body = [{
"points": [
[int(time.time()), ctxuser, int(wmicmd)]
],
"name": wmimoninfo,
"columns": ["time", "user", "value"]
}]
client.write_points(json_body, time_precision='s')
threads = []
cred = '-U'+forestname+'/'+wmiusr+'%'+wmipwd
wmidstip = "//"+cdcsrv
wmiselect = "select * from Citrix_Server"
wminamespace = "--namespace=Root/Citrix"
wmidelimiter = "--delimiter=;"
wmicmd = [wmic , cred , wmidstip , wmiselect , wminamespace , wmidelimiter ]
proc = subprocess.Popen(wmicmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
outputlines = filter(lambda x:len(x)>0,(line.strip() for line in proc.stdout))
ctxlist = []
for ctxinfo in outputlines[5:]:
if ctxinfo.split(';')[6] == zoneranking:
ctxlist.append([ctxinfo.split(';')[2], ctxinfo.split(';')[4]])
while 1:
i = 1
for ctxserver in ctxlist:
wmimonvalue = 0
ctxname = ctxserver[1]
ctxip = ctxserver[0]
response = os.system("ping -c 1 -t 2 " + ctxip)
if response == 0:
wmidstip = "//" + ctxip
wmiselect = "select "+wmiobject+" from "+wmiclass
wminamespace = '--namespace='+wminamespace_ini
wmidelimiter = "--delimiter=;"
wmicmd = [wmic , cred , wmidstip , wmiselect , wminamespace , wmidelimiter ]
print wmicmd
proc = subprocess.Popen(wmicmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
outputlines = filter(lambda x:len(x)>0,(line.strip() for line in proc.stdout))
if ((not any("ERROR" in s for s in outputlines)) and outputlines):
property_array = outputlines[1].split(";")
for ctxuserinfo in outputlines[2:]:
if (re.search(r"\(([A-Za-z0-9_]+)\)", ctxuserinfo.split(';')[9])):
m = re.search(r"\(([A-Za-z0-9_]+)\)", ctxuserinfo.split(';')[9])
ctx_username = m.group(1)
else:
ctx_username = ctxuserinfo.split(';')[9].replace(" ", "")
idx=2
for property_value in property_array[2:]:
wmimonvalue = ctxuserinfo.split(';')[idx]
if (idx != 9):
#wmimoninfo = ctx_username + "." + ctxname + "." + property_value
wmimoninfo = ctxname + "." + property_value
thread = myThread(i, str(ctxname), ctx_username, wmimonvalue, wmimoninfo )
thread.start()
threads.append(thread)
idx += 1
i += 1
for t in threads:
t.join()
print "Exiting Main Thread"
[config] FORESTNAME=domain.local WMIC=/usr/bin/wmic WMIUSR=wmiusername WMIPWD=wmipassword CDCSRV=10.11.0.1 DBSRVIP=10.11.0.2 DBSRVUSR=dbusr DBSRVPWD=dbpwd DB_SESSION_NAME=ctxmon [mon---1] WMICLASS=MetaFrame_Server WMIINSTANCE= WMIOBJECT=NumberOfActiveSessions WMINAMESPACE=Root/Citrix [mon---2] WMICLASS=MetaFrame_Server WMIINSTANCE= WMIOBJECT=NumberOfDisconnectedSessions WMINAMESPACE=Root/Citrix [mon---3] WMICLASS=MetaFrame_Server WMIINSTANCE= WMIOBJECT=NumberOfSessions WMINAMESPACE=Root/Citrix
#!/usr/bin/python
from __future__ import division
import socket
import ConfigParser
import os
import subprocess
import threading
import re
import time
from influxdb import InfluxDBClient
config = ConfigParser.RawConfigParser()
config.read(os.path.dirname(os.path.realpath(__file__))+'/config.ini')
forestname = config.get('config', 'FORESTNAME')
wmic = config.get('config', 'WMIC')
wmiusr = config.get('config', 'WMIUSR')
wmipwd = config.get('config', 'WMIPWD')
cdcsrv = config.get('config', 'CDCSRV')
dbsrvip = config.get('config', 'DBSRVIP')
dbsrvusr = config.get('config', 'DBSRVUSR')
dbsrvpwd = config.get('config', 'DBSRVPWD')
db_session_name = config.get('config', 'DB_SESSION_NAME')
sct = re.compile("^mon---", re.IGNORECASE)
client = InfluxDBClient(dbsrvip, 8096, dbsrvusr, dbsrvpwd, db_session_name)
monsct = filter(sct.search, config.sections())
threadLimiter = threading.BoundedSemaphore(value=200)
class myThread (threading.Thread):
def __init__(self, threadID, name, wmicmd, wmimoninfo):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.wmicmd = wmicmd
self.wmimoninfo = wmimoninfo
def run(self):
threadLimiter.acquire()
try:
print_adrepl(self.name, self.wmicmd, self.wmimoninfo )
finally:
threadLimiter.release()
def print_adrepl(threadName, wmicmd, wmimoninfo):
timeserie = threadName + '.' + wmimoninfo
proc = subprocess.Popen(wmicmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
errorlines = filter(lambda x:len(x)>0,(line.strip() for line in proc.stderr))
if errorlines :
t = 1
outputlines = filter(lambda x:len(x)>0,(line.strip() for line in proc.stdout))
if ((len(outputlines)>2) and (int(re.findall(r'\b\d+\b', outputlines[2:][0])[0])!=196)):
json_body = [{
"points": [
[int(time.time()), int(re.findall(r'\b\d+\b', outputlines[2:][0])[0])]
],
"name": timeserie,
"columns": ["time", "value"]
}]
client.write_points(json_body, time_precision='s')
threads = []
cred = '-U'+forestname+'/'+wmiusr+'%'+wmipwd
wmidstip = "//"+cdcsrv
wmiselect = "select * from Citrix_Server"
wminamespace = "--namespace=Root/Citrix"
wmidelimiter = "--delimiter=;"
wmicmd = [wmic , cred , wmidstip , wmiselect , wminamespace , wmidelimiter ]
proc = subprocess.Popen(wmicmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
outputlines = filter(lambda x:len(x)>0,(line.strip() for line in proc.stdout))
ctxlist = []
for ctxinfo in outputlines[5:]:
ctxlist.append([ctxinfo.split(';')[2], ctxinfo.split(';')[4]])
while 1:
i = 1
for ctxserver in ctxlist:
ctxname = ctxserver[1]
ctxip = ctxserver[0]
response = os.system("ping -c 1 -t 2 " + ctxip)
if response == 0:
wmidstip = "//" + ctxip
for monitor in monsct :
if config.get(monitor, 'WMIINSTANCE') != "" :
wmiinstance = " where name='"+config.get(monitor, 'WMIINSTANCE')+"'"
else :
wmiinstance = " "
wmiselect = "select " + config.get(monitor, 'WMIOBJECT') + " from " + config.get(monitor, 'WMICLASS') + wmiinstance
wminamespace = "--namespace=" + config.get(monitor, 'WMINAMESPACE')
wmidelimiter = "--delimiter=;"
wmicmd = [wmic , cred , wmidstip , wmiselect , wminamespace , wmidelimiter ]
wmimoninfo = config.get(monitor, 'WMICLASS')+"_"+config.get(monitor, 'WMIOBJECT')
thread = myThread(i, str(ctxname), wmicmd, wmimoninfo )
thread.start()
threads.append(thread)
i += 1
time.sleep(30)
for t in threads:
t.join()
print "Exiting Main Thread"
Last step, build the graphs
I have used the templating feature in Grafana to filter data using variables : one variable for the Citrix server name and the other for the username
You can download the following file and import it as a new dashboard :
Citrix-Session-Monitoring
A new feature has been added : annotation

Here an annotation is added when the Latency average is greater than 10s (=10000). You can adapt this value with your environment.
Do not hesitate to leave a comment if you need help…
My Powershell script categories
- Active Directory
- Cluster
- Database
- Exchange
- Files and folders
- Hardware
- Network
- Operating System
- PKI
- SCCM
- Service and process
- Tips
- VMWare




Hi Nicolas,
I’m always getting exiting main thread when running one of the python scripts, but no data is sent to influxdb.
Is there a way to debug the scripts? Already tried but am getting lost, since python is not a language I know very well.
Thanks in advance Johannes
Hi Nicolas,
I’m always getting exiting main thread when running one of the python scripts, but no data is sent to influxdb.
Is there a way to debug the scripts? Already tried but am getting lost, since python is not a language I know very well.
Thanks in advance Johannes
Hi. I realize this post is quite old, but.. I am trying to run the first python script and receiving the following error message. Very new to python so not sure what I am missing. Would greatly appreciate any help.
Traceback (most recent call last):
File “./ctxsession.py”, line 68, in
proc = subprocess.Popen(wmicmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
File “/usr/lib/python2.7/subprocess.py”, line 394, in __init__
errread, errwrite)
File “/usr/lib/python2.7/subprocess.py”, line 1047, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Hello Brandi,
The error is certainly caused by the missing of wmic tool on your box. Did you try to install it using one of this link :
– https://medium.com/@alberto.schiabel/how-to-compile-wmic-on-a-modern-gnu-linux-system-d4b0783bbf64
– https://www.aldeid.com/wiki/Wmic-linux
Keep me informed.
Sorry for the late feedback
Hi. I realize this post is quite old, but.. I am trying to run the first python script and receiving the following error message. Very new to python so not sure what I am missing. Would greatly appreciate any help.
Traceback (most recent call last):
File “./ctxsession.py”, line 68, in
proc = subprocess.Popen(wmicmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
File “/usr/lib/python2.7/subprocess.py”, line 394, in __init__
errread, errwrite)
File “/usr/lib/python2.7/subprocess.py”, line 1047, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Hello Brandi,
The error is certainly caused by the missing of wmic tool on your box. Did you try to install it using one of this link :
– https://medium.com/@alberto.schiabel/how-to-compile-wmic-on-a-modern-gnu-linux-system-d4b0783bbf64
– https://www.aldeid.com/wiki/Wmic-linux
Keep me informed.
Sorry for the late feedback