Hi to all of you, I am posting a help request as I need to create a PRTG Output for a superb Nvidia Grid License Overview Powershell Script that was created by John Billekens and that you can find here:

https://blog.j81.nl/2018/11/08/view-nvidia-grid-license-details-via-powershell/

The PowerShell scripts works perfectly even with multiple Nvidia Grid Licenses, the only issue I have not being a PowerShell Pro is to write to PRTG multiple licenses outputs.

Here is the script:

<#
.SYNOPSIS
    Get the Nvidia License Feature Details
.DESCRIPTION
    Get the Nvidia License Feature Details
.EXAMPLE
    Get-NvidiaLicencedFeatureDetails.ps1
    View all license details 
.EXAMPLE
    Get-NvidiaLicencedFeatureDetails.ps1 | Where-Object {$_.FeatureName -eq "GRID-Virtual-PC" }
    View all GRID-Virtual-PC licenses
.NOTES
    File Name : Get-NvidiaLicencedFeatureDetails.ps1
    Version   : v1.1
    Author    : John Billekens
    Requires  : PowerShell v5 and up
                Nvidia License server
.PARAMETER URI
    Specify the License server URI
    Default Value: http://localhost:8080/
.PARAMETER MaxIDs
    Specify the Max number of IDs being scanned, if you miss licenses, try to enter an higher ID (only for large companies or with multiple licenses)
    Default Value: 20
.LINK
    https://blog.j81.nl
#>
[CmdletBinding(DefaultParameterSetName = "URI")]
param (
    [Parameter(ParameterSetName = "URI", Position = 0)]
    [ValidatePattern('^(http[s]?)(:\/\/)([^\s,]+)')]
    [System.URI]$URI = "http://localhost:8080/",

    [Parameter(ParameterSetName = "Other")]
    [ValidateNotNullOrEmpty()]
    [String]$Protocol = "http",

    [Parameter(ParameterSetName = "Other")]
    [ValidateNotNullOrEmpty()]
    [string]$ServerFQDN = "localhost",

    [Parameter(ParameterSetName = "Other")]
    [ValidateNotNullOrEmpty()]
    [string]$ServerPort = "8080",

    [Parameter(ParameterSetName = "URI")]
    [Parameter(ParameterSetName = "Other")]
    [ValidateNotNullOrEmpty()]
    [Int]$MaxIDs = 20,

    [Parameter(ParameterSetName = "URI")]
    [Parameter(ParameterSetName = "Other")]
    [Switch]$Summary
)
#requires -version 5.0

if (-Not ($PSCmdlet.ParameterSetName -eq "URI")) {
    Write-Warning "-Protocol, -ServerFQDN and -ServerPort are legacy parameters"
    $URI = [System.URI]"{0}://{1}:{2}/" -f $Protocol, $ServerFQDN, $ServerPort
}
$LicencedFeatureDetails = [PSCustomObject]@()
$ErrorLoopCount = 0
$DataFound = $false
for ($i = 1; $i -le $MaxIDs; $i++) {
    try {
        $URL = "{0}licserver/manageFeatureUsage_featureDetails.action?feature.featureId={1}&page=1" -f $URI.AbsoluteUri, $i
        $Response = Invoke-WebRequest -UseBasicParsing -Uri $URL
        $FeatureName = try { $Response.RawContent | Where-Object { $_ -match '(?:<span class="heading1"><a title=")(?<FeatureName>[a-zA-Z-]+?)"' } | ForEach { $matches['FeatureName'] } } catch { $null }
        if (-not [String]::IsNullOrEmpty($FeatureName)) {
            $Version  = try { $Response.RawContent | Where-Object { $_ -match '(?:.+?(?=Version).+?(?=;));(?<Version>.+?(?= <))' } | ForEach { $matches['Version'] } } catch { $null }
            $TotalCount = try { $Response.RawContent | Where-Object { $_ -match '(?:.+?(?=Total count).+?(?=;));(?<TotalCount>.+?(?= <))' } | ForEach { $matches['TotalCount'] } } catch { $null }
            $Available = try { $Response.RawContent | Where-Object { $_ -match '(?:.+?(?=Available).+?(?=;));(?<Available>.+?(?= <))' } | ForEach { $matches['Available'] } } catch { $null }
            $CurrentUsage = try { $Response.RawContent | Where-Object { $_ -match '(?:.+?(?=Current Usage).+?(?=;));(?<CurrentUsage>.+?(?= <))' } | ForEach { $matches['CurrentUsage'] } } catch { $null }
            $ReservedCount = try { $Response.RawContent | Where-Object { $_ -match '(?:.+?(?=Reserved Count).+?(?=;));(?<ReservedCount>.+?(?= <))' } | ForEach { $matches['ReservedCount'] } } catch { $null }
            $VendorString = try { $Response.RawContent | Where-Object { $_ -match '(?:.+?(?=Vendor String).+?(?=;));(?<VendorString>.+?(?= <))' } | ForEach { $matches['VendorString'] } } catch { $null }
            $FeatureExpiry = try { $Response.RawContent | Where-Object { $_ -match '(?:.+?(?=Feature Expiry).+?(?=;));(?<FeatureExpiry>.+?(?=\s))' } | ForEach { $matches['FeatureExpiry'] } } catch { $null }

            try {
                $FeatureExpiry = [DateTime]::Parse($FeatureExpiry)
                $FeaturesDaysLeft = (New-TimeSpan -Start $(Get-Date) -End $FeatureExpiry).Days
                if ($FeaturesDaysLeft -lt 1) {
                    Write-Warning "License `"$FeatureName`" (ID: $i) is expired!"
                } elseif ($FeaturesDaysLeft -lt 90) {
                    Write-Warning "The `"$FeatureName`" (ID: $i) license will expire in $FeaturesDaysLeft days!"
                }
            } catch {
                $FeatureExpiry = $FeatureExpiry
                $FeaturesDaysLeft = -1
            }
            
            $CurrentUsageClients = [PSCustomObject]@{
                ClientID         = [string]""
                ClientIDType     = [string]""
                ClientType       = [string]""
                TotalCountServed = [Int32]0
                Expiry           = [Nullable[DateTime]]$null 
            }

            $Pattern = '(?:.+?(?=TRTableBorderBottom)(?s:.)+?(?=<a title=).+?(?=>))>(?<ClientID>.+?(?=<))(?:(?s:.)+?(?=<a title=).+?(?=>))>(?<ClientIDType>.+?(?=<))(?:(?s:.)+?(?=<a title=).+?(?=>))>(?<ClientType>.+?(?=<))(?:(?s:.)+?(?=[0-9]))(?<TotalCountServed>[0-9])(?:(?s:.)+?(?=[0-9]))(?<Expiry>[a-zA-Z0-9-:.]*)'
            $RxMatches = Select-String -InputObject $Response.RawContent -Pattern $pattern -AllMatches
            
            try {
                $CurrentUsageClients = $RxMatches.Matches | ForEach-Object { [PSCustomObject]@{
                    ClientID         = $(try { $_.Groups["ClientID"].Value } catch { $null })
                    ClientIDType     = $(try { $_.Groups["ClientIDType"].Value } catch { $null })
                    ClientType       = $(try { $_.Groups["ClientType"].Value } catch { $null })
                    TotalCountServed = $(try { [Int32]::Parse($($_.Groups["TotalCountServed"].Value)) } catch { $($_.Groups["TotalCountServed"].Value) })
                    Expiry           = $(try { [DateTime]::Parse($($_.Groups["Expiry"].Value)) } catch { $($_.Groups["Expiry"].Value) })
                                }
                }
            } catch { }
            $LicencedFeatureDetails += [PSCustomObject]@{
                ID                  = $i
                FeatureName         = $FeatureName
                Version             = $Version
                TotalCount          = $(try { [int]::Parse($TotalCount) } catch { $TotalCount } )
                Available           = $(try { [int]::Parse($Available) } catch { $Available } )
                CurrentUsage        = $(try { [int]::Parse($CurrentUsage) } catch { $CurrentUsage } )
                ReservedCount       = $(try { [int]::Parse($ReservedCount) } catch { $ReservedCount } )
                VendorString        = $VendorString
                FeatureExpiry       = $FeatureExpiry
                FeatureDaysLeft     = $FeaturesDaysLeft
                Uri                 = $URL
                CurrentUsageClients = $CurrentUsageClients
            }
        } elseif ($Data -like "*Error:*") {
            if ($DataFound) {
                $ErrorLoopCount++
            }
            if ($ErrorLoopCount -ge 20) {
                break
            }
        } 
    } catch {
        $ErrorLoopCount++
        Write-Verbose "Error Message: $_.Exception.Message"
    }
}
if ($Summary) {
    $LicencedFeatureDetails | Format-Table -Property ID,FeatureName,FeatureExpiry,TotalCount,CurrentUsage -AutoSize
} else {
    return $LicencedFeatureDetails
}

Here is the PowerShell Output when you have 3 Licenses Active

WARNING: The "GRID-Virtual-PC" (ID: 1) license will expire in 46 days!
WARNING: The "GRID-Virtual-PC" (ID: 3) license will expire in 46 days!


ID                  : 1
FeatureName         : GRID-Virtual-PC
Version             : 2.0
TotalCount          : 30
Available           : 30
CurrentUsage        : 0
ReservedCount       : 0
VendorString        : GRID-Virtual-PC-1
FeatureExpiry       : 08.08.2021 00:00:00
FeatureDaysLeft     : 46
Uri                 : http://nexcomp01:8080/licserver/manageFeatureUsage_featur
                      eDetails.action?feature.featureId=1&page=1
CurrentUsageClients : @{ClientID=; ClientIDType=; ClientType=; 
                      TotalCountServed=0; Expiry=}

ID                  : 2
FeatureName         : GRID-Virtual-PC
Version             : 2.0
TotalCount          : 3
Available           : 1
CurrentUsage        : 2
ReservedCount       : 0
VendorString        : GRID-Virtual-PC-1
FeatureExpiry       : 11.03.2022 00:00:00
FeatureDaysLeft     : 261
Uri                 : http://nexcomp01:8080/licserver/manageFeatureUsage_featur
                      eDetails.action?feature.featureId=2&page=1
CurrentUsageClients : {@{ClientID=0050569236C3; ClientIDType=ETHERNET; 
                      ClientType=VIRTUAL; TotalCountServed=1; 
                      Expiry=23.06.2021 18:14:59}, @{ClientID=005056922CEB; 
                      ClientIDType=ETHERNET; ClientType=VIRTUAL; 
                      TotalCountServed=1; Expiry=23.06.2021 18:16:59}}

ID                  : 3
FeatureName         : GRID-Virtual-PC
Version             : 2.0
TotalCount          : 30
Available           : 0
CurrentUsage        : 30
ReservedCount       : 0
VendorString        : GRID-Virtual-PC-2
FeatureExpiry       : 08.08.2021 00:00:00
FeatureDaysLeft     : 46
Uri                 : http://nexcomp01:8080/licserver/manageFeatureUsage_featur
                      eDetails.action?feature.featureId=3&page=1
CurrentUsageClients : {@{ClientID=00505692A44A; ClientIDType=ETHERNET; 
                      ClientType=VIRTUAL; TotalCountServed=1; 
                      Expiry=23.06.2021 16:29:59}, @{ClientID=005056923DB2; 
                      ClientIDType=ETHERNET; ClientType=VIRTUAL; 
                      TotalCountServed=1; Expiry=23.06.2021 16:30:59}, 
                      @{ClientID=005056928421; ClientIDType=ETHERNET; 
                      ClientType=VIRTUAL; TotalCountServed=1; 
                      Expiry=23.06.2021 16:47:59}, @{ClientID=0050569242AF; 
                      ClientIDType=ETHERNET; ClientType=VIRTUAL; 
                      TotalCountServed=1; Expiry=23.06.2021 17:18:59}...}

The desired channels in PRTG would be:

License ID
Total Count
Available
Current Usage
FeatureExpiry
FeatureDaysLeft

I managed to get the output to PRTG for one license but I am a little ashamed to post the end of my script as it's not very "clean", oh well

Write-Host "<prtg>"
           "<text>Feature Name: GRID-Virtual-PC / Feature Expiry: $FeatureExpiry / Feature Days Left: $FeaturesDaysLeft / Available License(s):$Available</text>"
Write-Host "<result>"
           "<channel>Total Count</channel>"
           "<value>$TotalCount</value>"
           "</result>"
Write-Host "<result>"
           "<channel>Available</channel>"
           "<value>$Available</value>"
           "</result>"
Write-Host "<result>"
           "<channel>Feature Days Left</channel>"
           "<value>$FeaturesDaysLeft</value>"
           "</result>"
Write-Host "</prtg>" 

I would be very grateful if someone could help me further, I promise I'll get myself a crush course in Advanced PowerShell Scripting.

Thank you in advance for your help.

BR Greg


Article Comments

Hello Greg,

Thank you for your message.

To return the information in PRTG, I would recommend to use a Foreach loop on your variable $LicencedFeatureDetails which contains an object for each licence, and then return the data by using the following code:

$prtg        = '' | select prtg
$results     = @()

try {
    $channels = @("TotalCount","Available","CurrentUsage","FeatureExpiry", "FeatureDaysLeft")
    foreach ($obj in $LicencedFeatureDetails){
        foreach ($channel in $channels){
            $result = @{
                channel     = "$channel (ID $($obj.ID))"
                value       = $obj."$channel"
            }
            $results += $result
        }   
    }
    $prtg.prtg        = '' | select result
    $prtg.prtg.result = $results

}catch{
    $prtg.prtg        = '' | select error
    $prtg.prtg.error  = 1
    $prtg.prtg | Add-Member -MemberType NoteProperty -Name 'text' -Value $null
    $prtg.prtg.text   = '{0} at line : {1}' -f $_.Exception.Message, $_.InvocationInfo.PositionMessage
}finally{
    $prtgJson = $prtg | ConvertTo-Json -Depth 5
    $prtgJson
    if ($prtg.prtg.error) {
        Exit 1
    } else {
        Exit 0
    }
}

Please, note that the code might need to be adapted and we can't provide support for it.

Here is an example of output provided by it :

{
  "prtg": {
    "result": [
      {
        "value": 10,
        "channel": "TotalCount (ID 1)"
      },
      {
        "value": 1,
        "channel": "Available (ID 1)"
      },
      {
        "value": 9,
        "channel": "CurrentUsage (ID 1)"
      },
      {
        "value": 10,
        "channel": "FeatureExpiry (ID 1)"
      },
      {
        "value": 10,
        "channel": "FeatureDaysLeft (ID 1)"
      }
...
    ]
  }
}

Regards.


Jun, 2021 - Permalink