Private/Export-CitrixUsageMetrics.ps1
<#
.SYNOPSIS Exports Citrix session usage metrics, including peak sessions, login time, and machine counts per Delivery Group, to a JSON file. .DESCRIPTION The Export-CitrixUsageMetrics function collects and exports usage analytics for specified Citrix Delivery Controllers over a specified date range. It queries data such as session summaries, failure logs, and machine counts via the Citrix OData Monitor service and outputs the data to a JSON file. The JSON file is named using the format: `CitrixMonitorData-[Environment]-[yyyy_MM].json`. .PARAMETER DeliveryControllers One or more Citrix Delivery Controller hostnames to retrieve data from. Required. .PARAMETER StartDate The beginning of the reporting period. Defaults to the previous day at 00:00:00. .PARAMETER EndDate The end of the reporting period. Defaults to the previous day at 23:59:59. .PARAMETER ExportFolder The folder path where the final JSON output should be saved. Defaults to `C:\temp`. .EXAMPLE Export-CitrixUsageMetrics -DeliveryControllers "ddc001", "ddc001" Exports usage metrics for the previous day from the specified delivery controllers and saves the results in `C:\temp`. .EXAMPLE Export-CitrixUsageMetrics -DeliveryControllers "ddc001" -StartDate "2025-03-01" -EndDate "2025-03-31" -ExportFolder "D:\Exports" Exports usage metrics for March 2025 and saves them to the specified export directory. .OUTPUTS [PSCustomObject[]] A list of delivery group metrics including: - DeliveryController - DeliveryGroup - MaxSessions - AvgLogonTimeSec - FailureCount - MachineCount .NOTES - Only active delivery groups with at least one machine are included. - Session summary granularity is adjusted based on the date range. - Requires the Citrix Monitor OData API to be accessible from the executing system. #> function Export-CitrixUsageMetrics { [CmdletBinding()] [OutputType('PSCustomObject')] param( [Parameter(Mandatory = $true)] [String[]]$DeliveryControllers, [Parameter()] [DateTime]$StartDate = (Get-Date).AddDays(-1).Date, [Parameter()] [DateTime]$EndDate = (Get-Date).AddDays(-1).Date.AddHours(23).AddMinutes(59).AddSeconds(59), [Parameter()] [string]$ExportFolder = "C:\\temp" ) $finalResult = @() $OutputObjects = @() foreach ($DeliveryController in $DeliveryControllers) { Write-Host "Querying data for Delivery Controller: $DeliveryController" $EnvironmentPrefix = if ($DeliveryController -match 'VAUS') { 'DR' } else { 'Prod' } function Invoke-CitrixODataQuery { param( [string]$DeliveryController, [string]$Endpoint, [string]$Query = '' ) $uri = "http://$DeliveryController/Citrix/Monitor/OData/v3/Data/$Endpoint$Query" $params = @{ Uri = $uri; Method = 'GET'; UseDefaultCredentials = $true; ErrorAction = 'Stop' } try { return Invoke-RestMethod @params } catch { Write-LogEntry -Message "Failed to query $Endpoint$Query on $DeliveryController : $_" return [PSCustomObject]@{ value = @() } } } $machines = Invoke-CitrixODataQuery -DeliveryController $DeliveryController -Endpoint 'Machines' -Query "?`$format=json&`$select=HostedMachineId,DesktopGroupId&`$filter=(LifecycleState eq 0) and (DesktopGroupId ne null) and (HostedMachineId ne null)" $deliveryGroups = Invoke-CitrixODataQuery -DeliveryController $DeliveryController -Endpoint 'DesktopGroups' -Query '?$format=json&$select=Id,Name' $activeGroupIds = $machines.value | Select-Object -ExpandProperty DesktopGroupId -Unique $deliveryGroups.value = $deliveryGroups.value | Where-Object { $activeGroupIds -contains $_.Id } Write-LogEntry -Message "Total Active Delivery Groups on $DeliveryController : $($deliveryGroups.value.Count)" $granularity = if ((New-TimeSpan -Start $StartDate -End $EndDate).TotalSeconds -le 3600) { '1' } elseif ((New-TimeSpan -Start $StartDate -End $EndDate).TotalSeconds -le 2592000) { '60' } else { '1440' } $sessionQuery = "?`$format=json&`$filter=(SummaryDate gt DateTime'$($StartDate.ToString('yyyy-MM-ddTHH:mm:ss'))') and (SummaryDate lt DateTime'$($EndDate.ToString('yyyy-MM-ddTHH:mm:ss'))') and (Granularity eq $granularity)" $sessions = Invoke-CitrixODataQuery -DeliveryController $DeliveryController -Endpoint 'SessionActivitySummaries' -Query $sessionQuery $failuresQuery = "?`$format=json&`$select=DesktopGroupId,FailureCount&`$filter=(SummaryDate gt DateTime'$($StartDate.ToString('yyyy-MM-ddTHH:mm:ss'))') and (SummaryDate lt DateTime'$($EndDate.ToString('yyyy-MM-ddTHH:mm:ss'))') and (FailureCategory eq 1) and (Granularity eq $granularity)" $failures = Invoke-CitrixODataQuery -DeliveryController $DeliveryController -Endpoint 'FailureLogSummaries' -Query $failuresQuery foreach ($dg in $deliveryGroups.value) { $dgId = $dg.Id $dgName = $dg.Name $maxSessions = ($sessions.value | Where-Object { $_.DesktopGroupId -eq $dgId } | Sort-Object -Property ConcurrentSessionCount -Descending | Select-Object -ExpandProperty ConcurrentSessionCount -First 1) if (-not $maxSessions) { $maxSessions = 0 } $logonCount = ($sessions.value | Where-Object { $_.DesktopGroupId -eq $dgId } | Measure-Object -Property TotalLogOnCount -Sum).Sum $logonDuration = ($sessions.value | Where-Object { $_.DesktopGroupId -eq $dgId -and $_.TotalLogOnCount -ge 1 } | Measure-Object -Property TotalLogOnDuration -Sum).Sum $avgLogon = if ($logonCount -gt 0 -and $logonDuration) { [int]($logonDuration / $logonCount / 1000) } else { 0 } $failureCount = ($failures.value | Where-Object { $_.DesktopGroupId -eq $dgId } | Measure-Object -Property FailureCount -Sum).Sum if (-not $failureCount) { $failureCount = 0 } $machineCount = ($machines.value | Where-Object { $_.DesktopGroupId -eq $dgId } | Select-Object -ExpandProperty HostedMachineId -Unique | Measure-Object).Count if ($machineCount -gt 0) { $finalResult += [PSCustomObject]@{ DeliveryController = $DeliveryController DeliveryGroup = $dgName MaxSessions = $maxSessions AvgLogonTimeSec = $avgLogon FailureCount = $failureCount MachineCount = $machineCount } } } $Output = [PSCustomObject]@{ StartDate = $StartDate.ToString("yyyy-MM-ddTHH:mm:ss") EndDate = $EndDate.ToString("yyyy-MM-ddTHH:mm:ss") Deployed = $EnvironmentPrefix DeliveryGroups = $finalResult | Where-Object { $_.DeliveryController -eq $DeliveryController } | Sort-Object -Property MaxSessions -Descending } $OutputObjects += $Output } if (-not (Test-Path $ExportFolder)) { New-Item -Path $ExportFolder -ItemType Directory | Out-Null } $monthYear = (Get-Date $StartDate).ToString("yyyy_MM") $envType = ($OutputObjects.Deployed | Select-Object -First 1) $finalPath = Join-Path $ExportFolder "CitrixMonitorData-$envType-$monthYear.json" $OutputObjects | ConvertTo-Json -Depth 5 | Out-File -FilePath $finalPath -Encoding UTF8 Write-LogEntry -Message "JSON export completed: $finalPath" return $finalResult | Sort-Object -Property MaxSessions -Descending } |