by Eltjo van Gulik, CTP
Since the introduction of Xenapp and Xendesktop 7, Citrix ships these products with the monitoring tool Director for all editions of its products. Director enables Citrix admins to proactively monitor their XenApp and XenDesktop environment in on-premises environments without the need for additional software or licenses.

In the latest State of the Union survey of 2018 by the VDI Like a Pro https://vdilikeapro.com/state-vdi-sbc-union-survey-2018/, 18 percent of the respondents that were polled when asked ‘Which public cloud (Remote App/DaaS) solution will you introduce or use?’ responded with Citrix Cloud on Azure as their preferred solution.

With the launch of Citrix Cloud and Virtual Apps & Desktops Service a while back, Director is the default tool of choice in a Cloud environment as well. But it comes with some caveats. Director in Citrix Cloud only saves 90 days of historical data.
https://docs.citrix.com/en-us/citrix-virtual-apps-desktops-service/director.html
So, what are the available options when you need access to historical data dating back more than 90 days, or when the default trends and reports can’t accommodate your needs?
Until recently, the only other choice you had was to rely on the custom reports feature of Director. But since, Citrix has made it possible to query the monitoring database (the same database that Director uses itself) directly yourself. This opens a whole new world of possibilities and is an important step in the maturity of Citrix Cloud in my opinion.
By leveraging Odata it is possible to retrieve the data from the monitoring database. Next, we have the possibility to base our own query on that data to create our own custom reports or use the data to setup a proprietary monitoring dashboard.
OData, short for Open Data Protocol, is a protocol that defines the best practices for consuming RESTful APIs. We can use OData to query the monitoring database with standard protocols like HTTP and methods such as REST (REpresentational State Transfer).
In order to access the monitoring data from Citrix Cloud, we need to authenticate ourselves. Citrix uses token-based authentication for this purpose. So, the first thing we need is to request a so-called bearer token. We can utilize PowerShell and the Citrix Cloud APIs to request the token.
Creating the Secure Client
First step in obtaining the bearer token is to create a ‘Secure Client.’ The Secure Client can be created from within the Citrix Cloud management portal in the ‘Identity and Access’ page.
After signing in to Citrix Cloud with an account with the appropriate permissions, select Identity and Access Management from the menu.

On the Identity and Access Management page, navigate to API Access.

On the API Access page, create a new secure client by giving it a name and clicking on ‘Create Client.’
The secure client that we’ve just created consists of an ID and an accompanying secret.
Be sure to note the Customer ID as well because we’ll need that piece of information later on.
(We also have the option to save the secure client to a csv file, because we’ll need this information later on too.)

Obtaining the bearer token
Now that we have the secure client, we can switch to PowerShell to create the bearer token. My own tool of choice for PowerShell is Visual Studio Code, but of course, the PowerShell ISE or even Notepad will do as well.
To obtain the bearer token we can use the getbearertoken function below:
function GetBearerToken {
param (
[Parameter(Mandatory=$true)]
[string] $clientId,
[Parameter(Mandatory=$true)]
[string] $clientSecret
)
$postHeaders = @{“Content-Type”=”application/json”}
$body = @{
“ClientId”=$clientId;
“ClientSecret”=$clientSecret
}$trustUrl = ” https://trust.citrixworkspacesapi.net/root/tokens/clients “
$response = Invoke-RestMethod -Uri $trustUrl -Method POST -Body (ConvertTo-Json $body) -Headers $postHeaders
$bearerToken = $response.token
return $bearerToken;
}
The function has two mandatory parameters, ClientID and Clientsecret. The function then uses the invoke-Restmethod. In the request, we pass the ClientID and ClientSecret values to Citrix Workspace API, and we’ll receive the bearer token as part of the response.
Now, bear in mind that function in its current form only has the bare minimum of functionality. No error handling is done. Every self-respecting coder would place the Invoke-RestMethod in a try-catch block. Just sayin’…
One other thing to note is that that the bearer token is only valid for 60 minutes, and Citrix will only allow a couple of connections to the API at a time (https://developer.cloud.com/authenticate_api_client.html)
Now with the function in place, we can feed in our own ClientID and Secret:
$clientId = “ClientID”
$clientSecret = “ClientSecret”
$bearerToken = GetBearerToken $clientId $clientSecret
$token = “CwsAuth Bearer=”+$bearerToken
Note the last line of the example above. The bearertoken we received from the function alone isn’t complete yet. My first tries to access the monitoring database with $bearerToken all failed. After some soul-searching and browsing thru the API documentation I stumbled upon the link below:
https://developer.cloud.com/call_api_bearer_token.html “Use the token property returned from the authentication API in the request Authorization header, prefixed by CwsAuth Bearer=”
Wow, that was a curveball…
Anyway, with that new knowledge, we can append the prefix ‘CwsAuth Bearer=’ to the $bearerToken into the variable $token to get the correct bearer token.
Querying the Monitoring Database part 1
With the correct bearer token in our possession we can now query the monitoring database.
First, we need to build the header for the request that we are going to send to the API. Remember what I said about the customer ID? We are going to need this now:
$headers = @{“Authorization” = “$token”; “Customer” = “Admin7255”}
$url = “https://CustomerID.xendesktop.net/Citrix/Monitor/OData/v4/Data/Users“
$result = Invoke-WebRequest -Uri $url -Headers $headers
So, in the header, we’ve got our bearer token and the customerID and in the URL variable we’ve got the OData URL (more on that later). We’ll pass both on to the Invoke-webrequest method and put the response into $result.
This might also be a good moment to talk about the kinds of data we can pull from the monitoring database. When we look back at the $url and analyze the url itself we can see that it consists of three parts: / we can break it down into three parts:
The customerID | the main part of the URL | and the data we want to retrieve: |
CustomerID.xendesktop.net | /Citrix/Monitor/OData/v4/Data | /Users |
With a slight variation to the URL, we can also retrieve data from the machines:
“https://CustomerID.xendesktop.net/Citrix/Monitor/OData/v4/Data/Machines“
Or data from the machine catalogs:
“https://CustomerID.xendesktop.net/Citrix/Monitor/OData/v4/Data/Catalogs“
Citrix has supplied database schema for this purpose: https://developer-docs.citrix.com/projects/monitor-service-odata-api/en/7.16/api-schema.pngWhen we put all this in practice, we now have the data in $result as a JSON. This is what that looks like in PowerShell:
$headers = @{“Authorization” = “$token”; “Customer” = ” wpzsew9uhl8x”}
$url = “https://CustomerID.xendesktop.net/Citrix/Monitor/OData/v4/Data/Machines”
$result = Invoke-WebRequest -Uri $url -Headers $headers
write-host $result.Content
$result.content | Out-File “c:\temp\machines.json”

Querying the Monitoring Database part 2
So, we’ve queried the monitoring database with PowerShell and got some data back. Cool beans! But we’re not limited to PowerShell. We can for instance also pull the data into Excel with Power Queries for example:
Start Excel with a blank workbook and select ‘Data from the lint’

Then Select ‘Get Data’ and ‘From other sources’

This will bring up the Power Query Editor. In the Power Query Editor switch to the Advanced Editor.

In the advanced editor use the following syntax:
let
Source = OData.Feed
(
“https://customerID.xendesktop.net/Citrix/monitor/OData/v4/data/Machines“,
null,
[
Headers =
[
Authorization = “Bearertoken“,
Customer = “CustomerID“
]
]
)
in
Source
Whereas the Source is the OData feed and the URL is the same URL we specified with PowerShell previous. In the headers again we will pass our authorization (our bearer token) and the CustomerID.
Make sure there are no syntax errors.

After clicking ‘Done’ you’ll be shown a preview of the data that has been collected.

Let’s give the query a name and save it.


A recent addition in Citrix Cloud for Director is that you now have the option to build you queries using the custom reports feature of Director and then copy the OData query from Director:



This makes building your OData queries a lot easier and requires fewer knowledge of the OData syntax.
Thats it for now, but stay tuned for more info on Citrix Cloud and OData in the near future.
Eltjo van Gulik