Using PowerShell to Collect User Logon Data from Citrix Monitoring OData Feed: Guest Blog Post by Bryan Zanoli

Share Button

LowRes Bryan Zanoli_2893 (2)For the last several years, I’ve had the honor and privilege of working closely with a colleague of mine, Bryan Zanoli. Bryan is incredibly sharp in the ways of Citrix, Microsoft and VMware virtualization and it’s been awesome working so closely together watching him hone his craft. Bryan recently embarked on a pet project to retrieve EdgeSight like reports (for you old-timers) from the Citrix Monitoring database (XenApp/XenDesktop 7.x). Some of these reports would show login times, durations, and usernames to be used for internal usage accounting. Bryan volunteered to share some of his key findings in his first guest blog post. If you have content you would like to contribute and be a guest blogger (or regular) on itvce.com, feel free to reach out to me at dane@itvce.com or on Twitter @youngtech so we can discuss. Without further ado, below is the guest blog post by Bryan Zanoli, you can find him on LinkedIn or on Twitter.


I recently pursued a way to programmatically track certain Citrix events through PowerShell. What I discovered proved very insightful and will hopefully provide you with additional tools for easier tracking, custom reporting, and automation in a Citrix XenApp/XenDesktop 7.x enviornment.

Getting Started with Citrix Monitoring

Before I continue, please see the following article by Dana Gutride, XenDesktop 7 Monitor Service – What Data is Available? In it you will find reference to the Citrix Monitoring service OData API. With the XML manipulation power of PowerShell, this data can be captured and leveraged to perform incredible tasks, such as determining which users logged on, how often, on a given date or time.

Another item to note: Citrix monitoring data is captured in the database for a period of time based on both licensing and XenDesktop site configuration. Retaining data for longer than 7 days requires XenApp or XenDesktop Platinum, and can be configured using the Set-MonitorConfiguration cmdlet. Platinum licensing offers 90 days of data retention by default but can be extended to a full year. Additional details can be found in this Citrix white paper here.

Building the Script

To view the available data, navigate to http://localhost/Citrix/Monitor/Odata/v1/Data, where “localhost” is the Fully Qualified Domain Name of your Delivery Controller. You will need to disable RSS Feed View if using Internet Explorer. When properly displayed you will see what looks like XML data. Using PowerShell, we can save this data, based on which object we wish to manipulate or capture.

To demonstrate, I’ll run through the process of obtaining session data and filter the data based on date.

Invoke-RestMethod –URI http://localhost/Citrix/Monitor/Odata/v1/Data/Sessions

You will need to provide administrative credentials to access the data.

As you will quickly see, we need to manipulate the data to obtain the desired results. Let’s try this instead:

$Sessions = Invoke-RestMethod –URI http://localhost/Citrix/Monitor/Odata/v1/Data/Sessions

$Sessions.Content.Properties

Now you will see the following properties output for each Session:

clip_image001

To display StartDate as an example, run the following:

$Sessions.Content.Properties.StartDate

This will display the start date for each session:

clip_image002

We now have what we need to filter this data. Next we will run the following command to grab all sessions with a start date of February 5, 2015.

$sessionDate = $sessions.Content.Properties | where { $_.StartDate –like “2015-02-05*” }

If you tried to run this, you may have noticed that even after verifying sessions existed on the specified date, the $sessionDate variable came up empty:

clip_image003

This is due to the formatting of the array and requires one additional object to be included in the command.

 $sessionDate = $sessions.Content.Properties | where { $_.StartDate.InnerText –like “2015-02-05*” }

Here we receive the same output as above for $sessions.Content.Properties, but only for sessions, which start date was February 05, 2015:

clip_image004

Now that you have been introduced to working with Citrix Monitoring data, review the script at the end of the blog to see how I managed to create a script that returns the username and logon count for a specified date. This is accomplished by taking the UserId from the session data and grabbing the corresponding username from that UserId:

$userIDs = $sessionDate.UserId.InnerText

We now have a list of UserIds:

clip_image005

We can take this list of UserIds and run it through a for-loop to grab the username for each UserId:

$userdata = Invoke-RestMethod –URI http://localhost/Citrix/Monitor/Odata/v1/Data/Users

$users = $userdata.content.properties

foreach ($userID in $userIDS) {

     $userName = $null

     $userName = $users | where {$_.Id.InnerText -eq $userID}

     write-host $userName.UserName

}

This will the username for each session, but there has got to be a better way to keep track of logon count:

clip_image006

So as to not spoil all the fun, I’ll offer the final running of the complete script as an exercise for the reader.

I’ll leave you with a possible use case. Imagine a service provider that is creating a charge back model in which they charge per hour or day as each user accesses an environment. With some slight modifications, the script could be made to run weekly or monthly and output the total hour or total day counts for each user. Modify the output so that it works with existing financial software, and the service provider now has a fully automated billing process!

The sky is the limit with the ability to easily extract the Citrix Monitoring data with PowerShell. These exact concepts could also be used to create a script that dynamically deploys or removes Virtual Desktops based on the number of users logging in each day!

What tasks could you accomplish with Citrix Monitoring data in the hands of PowerShell?

Click here to download the script shown below.

###########################################################

#

#      Script Name: CitrixMonUserLogon

#

#      Build:        2015.02.19 revision 1

#

#      Author:              Bryan Zanoli

#                    @BryanZanoli

#     

#      Date Created: 02-19-2015

#

#      Description: Connects to a XenDesktop 7.x site, collects

#                    User and Session data, and returns the total

#                    number of user logons per user, based

#                    on a specified date.

#

###########################################################

 

#Obtains the user credentials needed for accessing the XenDesktop Site monitoring information

$cred = Get-Credential

 

#Grab ‘Users’ data from XenDesktop site

#Replace localhost with FQDN of DDC if not running on DDC

$userdata = Invoke-RestMethod -uri “http://localhost/Citrix/Monitor/Odata/v1/Data/Users” -Credential $cred

 

#Populate User objects in $users variable

$users = $userdata.content.properties

 

#Obtain ‘Sessions’ data from XenDesktop Site

#Replace localhost with FQDN of DDC if not running on DDC

$sessiondata = Invoke-RestMethod -uri “http://localhost/Citrix/Monitor/Odata/v1/Data/Sessions” -Credential $cred

 

#Populate Session objects in $sessions variable

$sessions = $sessiondata.content.properties

 

#Create $date variable and set date to a temporary value

$date = “2015-01-06”

 

#Query the user for an updated date value, in specified format

$date = read-host “Please enter the date you wish to search (YYYY-MM-DD): “

 

#Returns the sessions for the specified date and populatess them into the $sessionDate1 variable

$sessionDate1 = $sessions | where {$_.startdate.InnerText -like $($date)*”}

 

#Populates the $userIDs variable with the userId value from the filtered sessions

$userIDs = $sessionDate1.UserId.InnerText

 

#Create a null array, used to capture and count user logons

$userObject = @()

 

#Begin for loop to process data

foreach ($userID in $userIDS) {

   

    #Create $userName variable and set the value to $null    

    $userName = $null

 

    #Filter $users so that only the user object with the given userId is returned

    $userName = $users | where {$_.Id.InnerText -eq $userID}

   

    #Check to see if the currently returned username already exists in the $userObject array

    if($userObject.UserName -contains $userName.UserName) {

       

       #Return the index of the location of the current user object

       $i = [array]::indexOf($userObject.UserName,($userName.UserName))

       

       #Since the user object already exists for userName, increase logon count by one

       ($userObject[$i]).count++

    }

 

    #If userName has not already been processed, proceed to object creation

    else{

      

       #Create a new System Object named $userObj

        $userObj = new-object System.Object

 

       #Add a member property of type [string] to the object, with the value of current UserName

        $userObj | add-member -memberType NoteProperty -Name UserName -Value $userName.UserName

       

       #Add a member property of type [int] to the object, with the value of 1, since this is the first occurance

       #of the current user

       $userObj | add-member -memberType NoteProperty -Name Count -Value 1

 

       #Add the newly created user object to the $userObject array

        $userObject += $userObj

    }

}

 

#Display Username and Logon Count

$userObject | fl UserName,Count

 

If you have any questions, comments, or simply want to leave me feedback, please feel free to do so below! Otherwise, enjoy and best of luck using PowerShell with Citrix Monitoring.

Bryan Zanoli

Share Button
  1. ShawnShawn01-26-2017

    Try making sure the credentials you store when prompted from the Get-Credential cmdlet are prefixed with your domain name. For example, DOMAIN\SAMACCOUNTNAME.

  2. sunhsinesunhsine01-03-2017

    Thanks for the article. I’m looking to pull a list of users that are connecting through the netscaler over a period of 7 days. Is this possible or is there a way to pull this from another source.

    Thanks
    Shineknox

    • Ralph HowlandRalph Howland03-25-2017

      You can get that data directly from the NetScaler. I have done it before. But now we forward all our NS data to a syslog server as the NS only stores data for 7 days.

  3. Ryan DeschaineRyan Deschaine12-29-2016

    #Returns the sessions for the specified date and populatess them into the $sessionDate1 variable
    $sessionDate1 = $sessions | where {$_.startdate.InnerText -like “$($date)*”}

    This command looks to be wrong, any idea what the fix is?

  4. BreeBree11-03-2016

    Excellent article Bryan, it has been very useful for me to help create a weekly report that contains all usernames with logon and logoff times.
    I do wonder if you know a way to convert the UTC datetime outputted to localtime using Powershell. Example of script I use
    $Cred = Get-Credential -credential “domain\username”

    $sessiondata = Invoke-RestMethod -uri “http://localhost/Citrix/Monitor/Odata/v1/Data/Sessions” -Credential $cred

    $sessions = $sessiondata.content.properties
    $sessions.enddate.innertext

    Output is
    2016-10-11T22:22:36.073
    2016-10-17T23:16:19.987
    2016-10-11T22:19:38.96
    2016-10-18T01:16:19.587
    2016-10-11T02:57:46.213
    2016-10-14T00:28:08.843
    2016-10-06T22:44:29.05
    2016-10-06T22:49:27.583
    2016-10-06T05:21:48.637
    2016-10-14T01:11:14.877
    2016-10-13T04:19:05.94
    2016-10-19T06:16:15.883
    2016-10-06T04:27:31.66

  5. magnusmagnus08-17-2016

    Hi
    I am trying to run the above but getting a 401 error
    Invoke-RestMethod : The remote server returned an error: (401) Unauthorized.

    I am using an account that is an admin in the domain as well as XD

    Any ideas on what I can look at?

    • ctxblogctxblog11-02-2016

      Hi Magnus,

      Try this : Invoke-RestMethod -UseDefaultCredentials –URI “http://localhost/Citrix/Monitor/Odata/v1/Data/Sessions”

Leave a Reply