{"id":5525,"date":"2019-04-29T16:52:25","date_gmt":"2019-04-30T00:52:25","guid":{"rendered":"https:\/\/www.atumvirt.com\/?p=5525"},"modified":"2019-04-29T16:52:25","modified_gmt":"2019-04-30T00:52:25","slug":"monitoring-license-expiration-in-logicmonitor","status":"publish","type":"post","link":"https:\/\/avtempwp.azurewebsites.net\/2019\/04\/monitoring-license-expiration-in-logicmonitor\/","title":{"rendered":"Monitoring License Expiration in LogicMonitor"},"content":{"rendered":"

This is a repost of a blog I did over on MyCUGC.org<\/a><\/p>\n

When you\u2019re 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\u2019t ever have a \u201cBad Day\u2122\u201d.<\/p>\n

The Citrix licensing documentation explains<\/a> the different sections of the license files.<\/p>\n

\"clip_image002\"<\/a><\/p>\n

Specifically, we\u2019re interested in section 3, \u201cINCREMENT\u201d, with the \u201cCSS_expiry_date\u201d and \u201cexp_date\u201d. The license counts themselves are actually available from the Citrix WMI provider, if you\u2019re interested in monitoring those, at \\root\\CitrixLicensing.<\/p>\n

To monitor these dates in LogicMonitor, we\u2019re going to set up a \u201cPropertySource\u201d to automatically discover servers running the \u201cCitrix Licensing\u201d service, then create a \u201cDataSource\u201d, which will query all licenses in the default path, and alarm on any SA or Expiry dates that are less than 30 days.<\/p>\n

To get started, let\u2019s create a \u201cPropertySource\u201d to assign a category \u201cCitrixLicense\u201d to the device.<\/p>\n

Settings->PropertySources->Add | PropertySource<\/p>\n

Add some descriptive information and \u201cGroup\u201d the property source for ease of finding it later.<\/p>\n

\"clip_image003\"<\/a><\/p>\n

For the PropertySource Script, paste the following GroovyScript in. Note, you can use PowerShell Scripts to do similar.<\/p>\n

import com.santaba.agent.groovyapi.win32.WMI;<\/p>\n

def host = hostProps.get(“system.hostname”);<\/p>\n

try<\/p>\n

{<\/p>\n

\/\/ get a list of running services<\/p>\n

def service_list = WMI.queryAll(host, “select * from win32_service”);<\/p>\n

def is_citrixLicenseServer = false;<\/p>\n

\/\/ enumerate each service as a map<\/p>\n

service_list.each<\/p>\n

{ service_map -><\/p>\n

\/\/ enumerate each of the fields in this service map<\/p>\n

service_map.each<\/p>\n

{ key, value -><\/p>\n

\/\/ is this an CitrixLicense service?<\/p>\n

if ((key == “NAME”) && value.contains(“Citrix Licensing”))<\/p>\n

{<\/p>\n

\/\/ yes, flag it<\/p>\n

is_citrixLicenseServer = true;<\/p>\n

}<\/p>\n

}<\/p>\n

}<\/p>\n

\/\/ did we locate an CitrixLicense service?<\/p>\n

if (is_citrixLicenseServer)<\/p>\n

{<\/p>\n

\/\/ yes, add the CitrixLicense to system.categories<\/p>\n

println “system.categories=CitrixLicense”;<\/p>\n

}<\/p>\n

return 0<\/p>\n

}<\/p>\n

catch (Exception e)<\/p>\n

{<\/p>\n

println e<\/p>\n

return 1<\/p>\n

}<\/p>\n

You can click \u201ctest script\u201d to see which devices will be matched. Click \u201cSave\u201d to save the PropertySource.<\/p>\n

You can see that if the service is found, we perform add \u201csystem.categories=CitrixLicense\u201d. We will use this category in the data source to specify which systems the discovery will apply to.<\/p>\n

Alternatively, you can use this Powershell script to apply categories for a variety of common Citrix roles.<\/p>\n

$hostname = “##Hostname##”<\/p>\n

add-type @”<\/p>\n

    using System.Net;<\/p>\n

    using System.Security.Cryptography.X509Certificates;<\/p>\n

    public class TrustAllCertsPolicy : ICertificatePolicy {<\/p>\n

        public bool CheckValidationResult(<\/p>\n

            ServicePoint srvPoint, X509Certificate certificate,<\/p>\n

            WebRequest request, int certificateProblem) {<\/p>\n

            return true;<\/p>\n

        }<\/p>\n

    }<\/p>\n

“@<\/p>\n

[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy<\/p>\n

$categories=@()<\/p>\n

$services=get-service -computername $hostname<\/p>\n

foreach($service in $services)<\/p>\n

{<\/p>\n

switch($service.DisplayName)<\/p>\n

    {<\/p>\n

“Citrix Licensing” { $categories+=”CitrixLicensing” }<\/p>\n

“Citrix Broker Service” { $categories+=”CitrixDeliveryController” }<\/p>\n

“Citrix PVS Stream Service” { $categories+=”CitrixPVS” }<\/p>\n

“Norskale Infrastructure Service” { $categories+=”CitrixWEM” }<\/p>\n

“Citrix Remote Broker Provider” { $categories+=”CitrixCloudConnector” }<\/p>\n

    }<\/p>\n

}<\/p>\n

$directorResult=Invoke-WebRequest -Uri “https:\/\/$hostname\/Director” -UseBasicParsing -Method HEAD<\/p>\n

if($directorResult.StatusCode -eq 200)<\/p>\n

{<\/p>\n

$categories+=”CitrixDirector”<\/p>\n

}<\/p>\n

$storefrontResult=Invoke-WebRequest -Uri “http:\/\/$hostname`:8000\/StorefrontMonitor\/GetSFServicesStatus” -UseBasicParsing<\/p>\n

if($storefrontResult.StatusCode -eq 200)<\/p>\n

{<\/p>\n

$categories+=”CitrixStorefront”<\/p>\n

}<\/p>\n

write-host “system.categories=$($categories -join “,”)”<\/p>\n

exit 0<\/p>\n

Next, we will create a DataSource. Settings -> DataSources -> Add DataSource<\/p>\n

\"clip_image005\"<\/a><\/p>\n

Fill in the descriptive information.<\/p>\n

\"clip_image006\"<\/a><\/p>\n

Relevant settings:<\/p>\n

Collect every: 1 day<\/p>\n

Collector: Batch Script<\/p>\n

Multi-Instance<\/p>\n

Enable Active Discovery<\/p>\n

Automatically Delete Instance | Delete Immediately<\/p>\n

Discovery Schedule: day<\/p>\n

Discovery method: Script, Embedded Powershell Script<\/p>\n

$hostname = ‘##SYSTEM.HOSTNAME##’<\/p>\n

$licenses=@()<\/p>\n

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

$path=”\\\\$hostname\\C$\\Program Files (x86)\\Citrix\\Licensing\\MyFiles”<\/p>\n

function Convert-SADateToDateTime{<\/p>\n

[Parameter(Mandatory=$true)]<\/p>\n

param ($inputString)<\/p>\n

$year=$inputString.Substring(0,4)<\/p>\n

$mon=$inputString.Substring(5,2)<\/p>\n

$day=$inputString.Substring(7,2)<\/p>\n

$builtString=”$year\/$mon\/$day”<\/p>\n

$DateTime = Get-Date($builtString)<\/p>\n

return $DateTime<\/p>\n

}<\/p>\n

function Convert-LicenseExpiryDate{<\/p>\n

[Parameter(Mandatory=$true)]<\/p>\n

param($inputString)<\/p>\n

if($inputString -eq “permanent”)<\/p>\n

{<\/p>\n

$dateString=”Jan-1-2099″<\/p>\n

}<\/p>\n

else<\/p>\n

{<\/p>\n

$dateString=$inputString<\/p>\n

}<\/p>\n

return (get-date $dateString)<\/p>\n

}<\/p>\n

$files= get-childitem -path $path -Filter *.lic | where-object {$_.name -ne “citrix_startup.lic”}<\/p>\n

if ($files)<\/p>\n

{<\/p>\n

foreach ($file in $files)<\/p>\n

{<\/p>\n

$currentFileContent=$null<\/p>\n

$currentFileContent=get-content $file.pspath<\/p>\n

$v=[Regex]::Matches($currentFileContent,$regexPattern)<\/p>\n

$SAExpirationDate=Convert-SADateToDateTime $($v[0].groups[1].Value)<\/p>\n

$LicenseExpiryDate=Convert-LicenseExpiryDate $($v[0].groups[2].Value)<\/p>\n

$licenses+=<\/p>\n

[pscustomobject][ordered]@{<\/p>\n

FileName = $file.Name<\/p>\n

SAExpiration = $SAExpirationDate<\/p>\n

LicenseExpiryDate= $LicenseExpiryDate<\/p>\n

DaysUntilSAExpiration = (($SAExpirationDate) – (get-date)).days<\/p>\n

DaysUntilLicenseExpiration = (($LicenseExpiryDate) – (get-date)).days<\/p>\n

} <\/p>\n

}<\/p>\n

for($i=0; $i -lt $licenses.Length; $i++)<\/p>\n

{<\/p>\n

write-host “CitrixLicense_$($Licenses[$i].FileName)##$($Licenses[$i].FileName)”<\/p>\n

}<\/p>\n

exit 0<\/p>\n

}<\/p>\n

else<\/p>\n

{<\/p>\n

exit 80009999<\/p>\n

} <\/p>\n

For the Active Discovery script, we\u2019re supplying a LogicMonitor variable, ##System.Hostname##, for use in connecting from our Collector<\/i> 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).<\/p>\n

Assuming you have devices in the \u201cApplies to\u201d 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<\/p>\n

\"clip_image008\"<\/a><\/p>\n

The WildValue and WildAlias are specified in the discovery script from this line:<\/p>\n

write-host “CitrixLicense_$($Licenses[$i].FileName)##$($Licenses[$i].FileName)”<\/p>\n

LogicMonitor parses stdOutput to construct these, per their documentation on Scripted Active Discovery.<\/a><\/p>\n

At this point, we\u2019re now ready to gather the collector attributes. Paste in this script<\/p>\n

$hostname = ‘##HOSTNAME##’<\/p>\n

$licenses=@()<\/p>\n

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

$path=”\\\\$hostname\\C$\\Program Files (x86)\\Citrix\\Licensing\\MyFiles”<\/p>\n

function Convert-SADateToDateTime{<\/p>\n

[Parameter(Mandatory=$true)]<\/p>\n

param ($inputString)<\/p>\n

$year=$inputString.Substring(0,4)<\/p>\n

$mon=$inputString.Substring(5,2)<\/p>\n

$day=$inputString.Substring(7,2)<\/p>\n

$builtString=”$year\/$mon\/$day”<\/p>\n

$DateTime = Get-Date($builtString)<\/p>\n

return $DateTime<\/p>\n

}<\/p>\n

function Convert-LicenseExpiryDate{<\/p>\n

[Parameter(Mandatory=$true)]<\/p>\n

param($inputString)<\/p>\n

if($inputString -eq “permanent”)<\/p>\n

{<\/p>\n

$dateString=”Jan-1-2099″<\/p>\n

}<\/p>\n

else<\/p>\n

{<\/p>\n

$dateString=$inputString<\/p>\n

}<\/p>\n

return (get-date $dateString)<\/p>\n

}<\/p>\n

$files= get-childitem -path $path | where-object { $_.name -ne “CITRIX.opt” -and $_.name -ne “citrix_startup.lic” }<\/p>\n

foreach ($file in $files)<\/p>\n

{<\/p>\n

$currentFileContent=$null<\/p>\n

$currentFileContent=get-content $file.pspath <\/p>\n

$v=[Regex]::Matches($currentFileContent,$regexPattern)<\/p>\n

$SAExpirationDate=Convert-SADateToDateTime $($v[0].groups[1].Value)<\/p>\n

$LicenseExpiryDate=Convert-LicenseExpiryDate $($v[0].groups[2].Value)<\/p>\n

$licenses+=<\/p>\n

[pscustomobject][ordered]@{<\/p>\n

FileName = $file.Name<\/p>\n

SAExpiration = $SAExpirationDate<\/p>\n

LicenseExpiryDate= $LicenseExpiryDate<\/p>\n

DaysUntilSAExpiration = (($SAExpirationDate) – (get-date)).days<\/p>\n

DaysUntilLicenseExpiration = (($LicenseExpiryDate) – (get-date)).days<\/p>\n

}<\/p>\n

}<\/p>\n

foreach($license in $licenses)<\/p>\n

{<\/p>\n

“CitrixLicense_$($license.Filename)`.DaysUntilSAExpiration=$($license.DaysUntilSAExpiration)”<\/p>\n

“CitrixLicense_$($license.Filename)`.DaysUntilLicenseExpiration=$($license.DaysUntilLicenseExpiration)”<\/p>\n

}<\/p>\n

exit 0 <\/p>\n

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 \u201cpermanent\u201d is found, we convert that to January 1, 2099. Since the SA expiry date isn\u2019t a format that \u201cget-date\u201d understands, we convert it to a format that will work for the cmdlet.<\/p>\n

Finally, for each discovered license, we output text to stdOutput in the key=value format that LogicMonitor will parse.<\/p>\n

CitrixLicense_FID_19445f95_d1a0_4594_81df_e871e87a4678.lic.DaysUntilSAExpiration=356<\/p>\n

CitrixLicense_FID_19445f95_d1a0_4594_81df_e871e87a4678.lic.DaysUntilLicenseExpiration=386<\/p>\n

CitrixLicense_FID__23f6bf6d_161c87582c5__26bf.lic.DaysUntilSAExpiration=-42<\/p>\n

CitrixLicense_FID__23f6bf6d_161c87582c5__26bf.lic.DaysUntilLicenseExpiration=-12<\/p>\n

Finally, we create the actual datapoints from the output of the collection. Click \u201cAdd DataPoint\u201d and create 2 gauge datapoints.<\/p>\n

\"clip_image010\"<\/a><\/p>\n

\"clip_image011\"<\/a><\/p>\n

Set the alert threshold<\/p>\n

\"clip_image012\"<\/a><\/p>\n

Then click save.<\/p>\n

Once you\u2019ve 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.<\/p>\n

\"clip_image014\"<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"

This is a repost of a blog I did over on MyCUGC.org When you\u2019re 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 […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[10,35],"tags":[86,97,98],"_links":{"self":[{"href":"https:\/\/avtempwp.azurewebsites.net\/wp-json\/wp\/v2\/posts\/5525"}],"collection":[{"href":"https:\/\/avtempwp.azurewebsites.net\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/avtempwp.azurewebsites.net\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/avtempwp.azurewebsites.net\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/avtempwp.azurewebsites.net\/wp-json\/wp\/v2\/comments?post=5525"}],"version-history":[{"count":0,"href":"https:\/\/avtempwp.azurewebsites.net\/wp-json\/wp\/v2\/posts\/5525\/revisions"}],"wp:attachment":[{"href":"https:\/\/avtempwp.azurewebsites.net\/wp-json\/wp\/v2\/media?parent=5525"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/avtempwp.azurewebsites.net\/wp-json\/wp\/v2\/categories?post=5525"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/avtempwp.azurewebsites.net\/wp-json\/wp\/v2\/tags?post=5525"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}