Monitoring License Expiration in LogicMonitor

By Preston Gallwas posted 04-16-2019 10:06 PM

  

When you’re responsible for the care and feeding of your Citrix environment, it is important to keep tabs on your licensing status. In particular, if you have a license type that expires, it is important to monitor that data point to ensure you don’t ever have a “Bad Day™.”

The Citrix licensing documentation explains the different sections of the license files.


Specifically, we’re interested in section 3, “INCREMENT,” with the “CSS_expiry_date” and “exp_date”.  The license counts themselves are actually available from the Citrix WMI provider, if you’re interested in monitoring those.

To monitor these dates in LogicMonitor, we’re going to set up a “PropertySource” to automatically discover servers running the “Citrix Licensing” service, then create a “DataSource,” which will query all licenses in the default path, and alarm on any SA or Expiry dates that are less than 30 days.

To get started, let’s create a “PropertySource” to assign a category “CitrixLicense” to the device.

Settings->PropertySources->Add | PropertySource

Add some descriptive information and “Group” the property source for ease of finding it later.

 

For the PropertySource Script, paste the following GroovyScript in. Note, you can use PowerShell Scripts to do similar.


import com.santaba.agent.groovyapi.win32.WMI;

def host = hostProps.get("system.hostname");

 

try

{

    // get a list of running services

    def service_list = WMI.queryAll(host, "select * from win32_service");

 

    def is_citrixLicenseServer = false;

 

    // enumerate each service as a map

    service_list.each

    { service_map ->

 

        // enumerate each of the fields in this service map

        service_map.each

        { key, value ->

 

            // is this a CitrixLicense service?

            if ((key == "NAME") && value.contains("Citrix Licensing"))

            {

                // yes, flag it

                is_citrixLicenseServer = true;

            }

        }

    }

 

    // did we locate a CitrixLicense service?

    if (is_citrixLicenseServer)

    {

        // yes, add the CitrixLicense to system.categories

        println "system.categories=CitrixLicense";

    }

 

    return 0

 

}

catch (Exception e)

{

    println e

    return 1

}

 

Add the proper "Applies to" such as Windows(). You can click “test script” to see which devices will be matched. Click “Save” to save the PropertySource.

You can see that if the service is found, we perform add “system.categories=CitrixLicense”.  We will use this category in the data source to specify which systems the discovery will apply to.

Alternatively, you can use this Powershell script to apply categories for a variety of common Citrix roles.

$hostname = "##Hostname##"

 

add-type @"

    using System.Net;

    using System.Security.Cryptography.X509Certificates;

    public class TrustAllCertsPolicy : ICertificatePolicy {

        public bool CheckValidationResult(

            ServicePoint srvPoint, X509Certificate certificate,

            WebRequest request, int certificateProblem) {

            return true;

        }

    }

"@

[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

 

$categories=@()

$services=get-service -computername $hostname

foreach($service in $services)

{

       switch($service.DisplayName)

    {

        "Citrix Licensing" { $categories+="CitrixLicensing" }

        "Citrix Broker Service" { $categories+="CitrixDeliveryController" }

        "Citrix PVS Stream Service" { $categories+="CitrixPVS" }

        "Norskale Infrastructure Service" { $categories+="CitrixWEM" }

        "Citrix Remote Broker Provider" { $categories+="CitrixCloudConnector" }

    }

}

 

 

 

$directorResult=Invoke-WebRequest -Uri "https://$hostname/Director"  -UseBasicParsing -Method HEAD

if($directorResult.StatusCode -eq 200)

{

    $categories+="CitrixDirector"

}

 

$storefrontResult=Invoke-WebRequest -Uri "http://$hostname`:8000/StorefrontMonitor/GetSFServicesStatus"  -UseBasicParsing

if($storefrontResult.StatusCode -eq 200)

{

    $categories+="CitrixStorefront"

}

write-host "system.categories=$($categories -join ",")"

exit 0

 

 

Next, we will create a DataSource.  Settings -> DataSources -> Add DataSource


Fill in the descriptive information.

Relevant settings:

Collect every: 1 day

Collector: Batch Script

Multi-Instance

Enable Active Discovery

Automatically Delete Instance | Delete Immediately

Discovery Schedule: day

Discovery method: Script, Embedded Powershell Script

 

$hostname = '##SYSTEM.HOSTNAME##'

 

$licenses=@()

$regexPattern="INCREMENT.*(\d{4}.\d{4}) (\d{1}?-((jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)-2\d{3})|permanent)"

$path="\\$hostname\C$\Program Files (x86)\Citrix\Licensing\MyFiles"

 

 

function Convert-SADateToDateTime{

    [Parameter(Mandatory=$true)]

    param ($inputString)

    $year=$inputString.Substring(0,4)

    $mon=$inputString.Substring(5,2)

    $day=$inputString.Substring(7,2)

    $builtString="$year/$mon/$day"

    $DateTime = Get-Date($builtString)

 

    return $DateTime

}

function Convert-LicenseExpiryDate{

    [Parameter(Mandatory=$true)]

    param($inputString)

    if($inputString -eq "permanent")

    {

        $dateString="Jan-1-2099"

    }

    else

    {

        $dateString=$inputString

    }

 

   

    return (get-date $dateString)

}

 

$files= get-childitem -path $path -Filter *.lic | where-object {$_.name -ne "citrix_startup.lic"}

if ($files)

    {

    foreach ($file in $files)

    {

        $currentFileContent=$null

        $currentFileContent=get-content $file.pspath

        $v=[Regex]::Matches($currentFileContent,$regexPattern)

 

        $SAExpirationDate=Convert-SADateToDateTime $($v[0].groups[1].Value)

    $LicenseExpiryDate=Convert-LicenseExpiryDate $($v[0].groups[2].Value)

 

    $licenses+=

        [pscustomobject][ordered]@{

        FileName = $file.Name

        SAExpiration = $SAExpirationDate

        LicenseExpiryDate= $LicenseExpiryDate

        DaysUntilSAExpiration = (($SAExpirationDate) - (get-date)).days

        DaysUntilLicenseExpiration = (($LicenseExpiryDate) - (get-date)).days

       

    }

 

    }

    for($i=0; $i -lt $licenses.Length; $i++)

 

    {

    write-host  "CitrixLicense_$($Licenses[$i].FileName)##$($Licenses[$i].FileName)"

    }

    exit 0

}

else

{

    exit 80009999

}

 

 

For the Active Discovery script, we’re supplying a LogicMonitor variable, ##System.Hostname##, for use in connecting from our Collector machine to the Citrix licensing service. Note, in order to do this, the collector service account will need to have UNC access to the remote machine(s).

Assuming you have devices in the “Applies to” category, you should be able to test script (for active discovery) to see which licenses are detected. In my case, the following items were found:

The WildValue and WildAlias are specified in the discovery script from this line:

    write-host  "CitrixLicense_$($Licenses[$i].FileName)##$($Licenses[$i].FileName)"

LogicMonitor parses stdOutput to construct these, per their documentation on Scripted Active Discovery.

 

At this point, we’re now ready to gather the collector attributes. Paste in this script:

$hostname =     '##HOSTNAME##'

 

$licenses=@()

$regexPattern="INCREMENT.*(\d{4}.\d{4}) (\d{1}?-((jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)-2\d{3})|permanent)"

$path="\\$hostname\C$\Program Files (x86)\Citrix\Licensing\MyFiles"

 

 

function Convert-SADateToDateTime{

    [Parameter(Mandatory=$true)]

    param ($inputString)

    $year=$inputString.Substring(0,4)

    $mon=$inputString.Substring(5,2)

    $day=$inputString.Substring(7,2)

    $builtString="$year/$mon/$day"

    $DateTime = Get-Date($builtString)

 

    return $DateTime

}

function Convert-LicenseExpiryDate{

    [Parameter(Mandatory=$true)]

    param($inputString)

    if($inputString -eq "permanent")

    {

        $dateString="Jan-1-2099"

    }

    else

    {

        $dateString=$inputString

    }

 

   

    return (get-date $dateString)

}

 

$files= get-childitem -path $path | where-object { $_.name -ne "CITRIX.opt" -and $_.name -ne "citrix_startup.lic" }

foreach ($file in $files)

{

    $currentFileContent=$null

    $currentFileContent=get-content $file.pspath

    $v=[Regex]::Matches($currentFileContent,$regexPattern)

 

    $SAExpirationDate=Convert-SADateToDateTime $($v[0].groups[1].Value)

    $LicenseExpiryDate=Convert-LicenseExpiryDate $($v[0].groups[2].Value)

 

    $licenses+=

        [pscustomobject][ordered]@{

        FileName = $file.Name

        SAExpiration = $SAExpirationDate

        LicenseExpiryDate= $LicenseExpiryDate

        DaysUntilSAExpiration = (($SAExpirationDate) - (get-date)).days

        DaysUntilLicenseExpiration = (($LicenseExpiryDate) - (get-date)).days

       

    }   

}

foreach($license in $licenses)

{

 "CitrixLicense_$($license.Filename)`.DaysUntilSAExpiration=$($license.DaysUntilSAExpiration)"

 "CitrixLicense_$($license.Filename)`.DaysUntilLicenseExpiration=$($license.DaysUntilLicenseExpiration)"

}

exit 0


This script will retrieve all licenses on the specified host, then for each license discovered, it uses a regex pattern to extract the dates. If the word “permanent” is found, we convert that to January 1, 2099. Since the SA expiry date isn’t a format that “get-date” understands, we convert it to a format that will work for the cmdlet.

Finally, for each discovered license, we output text to stdOutput in the key=value format that LogicMonitor will parse. 

CitrixLicense_FID_19445f95_d1a0_4594_81df_e871e87a4678.lic.DaysUntilSAExpiration=356

CitrixLicense_FID_19445f95_d1a0_4594_81df_e871e87a4678.lic.DaysUntilLicenseExpiration=386

CitrixLicense_FID__23f6bf6d_161c87582c5__26bf.lic.DaysUntilSAExpiration=-42

CitrixLicense_FID__23f6bf6d_161c87582c5__26bf.lic.DaysUntilLicenseExpiration=-12 

 

Finally, we create the actual datapoints from the output of the collection.  Click “Add DataPoint” and create 2 gauge datapoints.

Set the alert threshold

Then click save.

Once you’ve saved your datapoint, any matching devices will run active discovery and you should now see your licenses associated with that device!  Based on your notification/escalation settings within LogicMonitor, you now have actionable monitoring of a vital piece of Citrix infrastructure.