Citrix Virtual Apps and Desktop HTML Dashboard with PowerShell – Delivery Group capacity
Updated 27-08-2020: percentage rebuild, CSS optimisation and some small changes to code
Updated 29-09-2020: fixed issue with user sessions which are in maintenance
The idea to make this script originates from missing a few features in Citrix Director. A few of the options/views we miss in Citrix Director are:
- Sum of two CVAD Sites when using site aggregation.
- Warning or critical warning when the amount of free VDI’s is under a certain threshold.
- Combined view of two CVAD sites delivery group usage.
- Machines in maintenance but Registered can cause an outage because machines are not available.
The script that I created is preconfigured for two CVAD Sites. See below for an example script output:

Features of the script:
- Automatically get all Delivery Groups.
- Filter out specific Delivery Groups Names and amounts of Total Desktops.
- Create a HTML page where a Delivery Group under 10% is colored orange and a Delivery Group under 5% is colored red.
- Sum of Delivery Groups in both CVAD Sites
- Checking which VDI’s are in maintenance and are Registered. The script will subtract this from the Available amount.
The script has a few paramaters defined which can be changed to own liking:
$ExclusionList = "DU.*|.*_"
$Threshold = 15
$title = "VDI Monitoring - Dashboard - $(get-date)"
What needs to be changed in order to run the PowerShell script:
$DDCXD1 = "CVADDDCsite1" $DDCXD2 = "CVADDDCsite2" $html | out-file "\\yourlocation\DeliveryGroupTotals.html"
Complete script:
#############################################################################
#
# Name : VDI Monitoring Dashboard
# Created By: Silas Arentsen
# Purpose : Get information for all Delivery Groups and present this in a simple table
# Warn when delivery group availability minus machines in maintenance mode reaches 10% and critical warning when 5% is reached
##############################################################################
Add-PSSnapin citrix*
#Declare the DeliveryControllers for each site, if applicable
$DDCXD1 = "CVADDDCsite1"
$DDCXD2 = "CVADDDCsite2"
#List of Delivery group names which are not processed in the script
$ExclusionList = "DU.*|.*_"
#Minimal amount of total desktops needed before the Delivery Group shows up in the HTML
$Threshold = 15
$Xdsite01 = Get-BrokerDesktopGroup -AdminAddress $DDCXD1 | Select Name, DesktopsAvailable, TotalDesktops | Where Name -notmatch $ExclusionList
$Xdsite02 = Get-BrokerDesktopGroup -AdminAddress $DDCXD2 | Select Name, DesktopsAvailable, TotalDesktops | Where Name -notmatch $ExclusionList
$Inventory = New-Object System.Collections.ArrayList
foreach ($DG in $Xdsite01) {
$ComputerInfo = New-Object System.Object
if ([int]$DG.TotalDesktops -gt $Threshold) {
$MM1 = (Get-BrokerMachine -MaxRecordCount 90000 –adminaddress $DDCXD1 -DesktopGroupName $DG.Name -InMaintenanceMode $true | where {$_.RegistrationState -EQ "Registered" -and $_.SessionCount -notlike "1"} | Select-Object DnsName | Measure-Object).count
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "Name" -Value $DG.Name.ToString()
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "DesktopsAvailable" -Value ($DG.DesktopsAvailable - $MM1)
$ComputerInfo | Add-Member -MemberType NoteProperty -Name "TotalDesktops" -Value $DG.TotalDesktops
$Inventory.Add($ComputerInfo) | Out-Null
}
Else {}
}
foreach ($DG in $Xdsite02) {
$ComputerInfo2 = New-Object System.Object
if ([int]$DG.TotalDesktops -gt $Threshold) {
$MM3 = (Get-BrokerMachine -MaxRecordCount 90000 –adminaddress $DDCXD2 -DesktopGroupName $DG.Name -InMaintenanceMode $true | where {$_.RegistrationState -EQ "Registered" -and $_.SessionCount -notlike "1"} | Select-Object DnsName | Measure-Object).count
$ComputerInfo2 | Add-Member -MemberType NoteProperty -Name "Name" -Value $DG.Name.ToString()
$ComputerInfo2 | Add-Member -MemberType NoteProperty -Name "DesktopsAvailable" -Value ($DG.DesktopsAvailable - $MM3)
$ComputerInfo2 | Add-Member -MemberType NoteProperty -Name "TotalDesktops" -Value $DG.TotalDesktops
$Inventory.Add($ComputerInfo2) | Out-Null
}
Else {}
}
#Count totals of both sites if a Delivery group is present in both
$Inventory = $Inventory | Group-Object -Property Name | Select-Object -Property @{Name='ProcentAvailable'; Expression='Procent'}, @{Name='Name'; Expression='Name'}, @{Name='DesktopsAvailable'; Expression={($_.Group| Measure-Object -Sum -Property DesktopsAvailable).Sum}}, @{Name='TotalDesktops'; Expression={($_.Group| Measure-Object -Sum -Property TotalDesktops).Sum}}
$Header = "
table
{
Margin: 0px 0px 0px 4px;
Border: 1px solid rgb(190, 190, 190);
Font-Family: Tahoma;
Font-Size: 24pt;
Background-Color: rgb(252, 252, 252);
}
th
{
Text-Align: Left;
Color: rgb(150, 150, 220);
Padding: 1px 4px 1px 4px;
}
td
{
Vertical-Align: Top;
Padding: 1px 4px 1px 4px;
}
tr.under-5 td
{
background-color: red;
color: white;
}
tr.under-10 td
{
background-color: orange;
color: white;
}
h3
{
margin-top: -25;
margin-bottom: 0;
}
tr:nth-child(even) {
background-color: #efefef;
}
"
$Inventory = $Inventory | Sort-Object TotalDesktops -Descending
$title = "VDI Monitoring - Dashboard - $(get-date)"
$refresh = '<meta http-equiv="refresh" content="60; URL=http://YourLocation/DeliveryGroupTotals.html">'
$html = "<html>
<head>
<title>$title</title>
$refresh
<style>`n`
$Header`n`
</style>
</head>
<body>"
$html += "`n`t`t<H3><br><i>Run on: $(get-date)</i></H3>"
$html += "`n`t`t<table>`
`n`t`t`t<tr>`
`n`t`t`t`t<th>ProcentAvailable</th>`
`n`t`t`t`t<th>Name</th>`
`n`t`t`t`t<th>DesktopsAvailable</th>`
`n`t`t`t`t<th>TotalDesktops</th>`
`n`t`t`t</tr>"
foreach ($item in $Inventory) {
foreach($percentage in $item.Name) {
$name = $item.Name
$ProcentAvailable = [math]::round(($item.DesktopsAvailable / $item.TotalDesktops) * 100)
$DesktopsAvailable = $item.DesktopsAvailable
$TotalDesktops = $item.TotalDesktops
if($ProcentAvailable -le 5) {
$rowclass = "under-5"
}
elseif($ProcentAvailable -le 10) {
$rowclass = "under-10"
}
else {
$rowclass = ""
}
$html += "`n`t`t`t<tr class=`"$rowclass`">`
`n`t`t`t`t<td>$ProcentAvailable</td>`
`n`t`t`t`t<td>$name</td>`
`n`t`t`t`t<td>$DesktopsAvailable</td>`
`n`t`t`t`t<td>$TotalDesktops</td>`
`n`t`t`t</tr>"
}
}
$html += "`n`t`t</table>"
$html += "`n`t</body>`n</html>"
$html | out-file "\\YourLocation\DeliveryGroupTotals.html"

Started working in IT since 2016 for several Managed Service Providers. IT is always changing, which is why I like to learn from others. A challenge is never too much and will try to get my work up to a higher level each time.
Personal characteristics:
Motivated, calm, sincere and honest
Free time spending:
Kickboxing, technology, cars and day trips
Fantastic script. I discovered the Get-BrokerDesktopGroup command just yesterday and could not get it to do what I wanted. Could not pipe to it, could not get it work with a ForEach. I have a journeyman’s skillset at best with POSH, so this is a great teaching tool and a super useful script example for some VDI dashboards I’m creating. The beauty here is how you combined Get-BrokerDesktopGroup with Get-BrokerMachine.