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
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