The Citrix Virtual Apps and Desktops & Desktops as a Service Health Check Script on Steroids

UPDATE: Version 1.5.9 released on 3rd March 2026. See below for all the details.

Since November 2014 many of us have been using the amazing Sacha Thomet’s XenApp and XenDesktop Health Check Script. I’ve made my own modifications to it over the years, but never contributed and shared anything publicly until June 2025. My motivation is to give the community some amazing visibility of their Citrix environments that they’ve never had before. I took the last release from Sacha, which was the February 2022 update, together with some modules I’d previously written, and overhauled the whole process from top to bottom, and wrote even more modules. Sacha has kindly committed my pull requests to his GitHub repository, which officially adds me as Contributor!

CVAD & DaaS Health Check Script on Steroids

The commits of versions 1.4.7 (10th June 2025) through to 1.5.9 (3rd March 2026) are all from yours truly. I’ve actually taken the script from 1,945 lines to 8,210 lines. That’s a huge 322.1% increase. Admittedly, there is also a lot of added documentation and formatting changes to make it easier for others to follow and contribute. But it’s still a massive jump in features and recode.

My requirements in a nutshell:

  • Improve the speed and reliability of processing all the remote tests.
  • Primarily use WinRM and fall back to WMI (DCOM) for all connectivity tests where possible. Having said that, some of the tests are WinRM only, and a couple still use WMI only.
  • Not rely on ping (ICMP) to be successful for tests to progress. In an OT environment, ICMP is typically blocked.
  • Call a single instance of the script to process multiple on-prem sites from a central management server. My use case for this is OT, where each mine site will have it’s own CVAD site.
  • If processing multiple sites, process them in parallel using PowerShell runspaces. It makes sense to do it this way and reduce the time the script takes to run.
  • Ensure it works with Citrix Cloud (DaaS) using the PowerShell SDK, so it’s still valid in the Corporate IT environment where we may also use Citrix Cloud.
  • Include information for lifecycle planning, such as Windows caption. OS build number and VDA version was already part of the existing script from Sacha.
  • Include VM sizing information, such as logical processors, sockets, cores and total physical RAM. This helps identify misconfigurations.
  • Methods to determine PVS, MCS and Standalone session host configurations.
  • Tests to check Nvidia driver version and if the machine has acquired/renewed a license successfully. This is important to ensure the GPU driver is not running n a degraded state, which will cause performance and application errors.
  • RDS licensing checks to get the Terminal Server mode, grace period, license type, license name, and license server list. This helps identify problems and misconfigurations. The idea came from Manuel Winkel‘s Get-RDSGracePeriod function used in his Citrix Morning Report script.
  • Tests to check if FSLogix, UPM and WEM are installed, running and active.
  • Tests to check if the CrowdStrike Falcon Agent is installed and running, as well as listing the Group Tags used during installation.
  • Provide a “Stuck Sessions” table, which shows a potential list of sessions that may need to be logged off or VDAs restarted.
  • For the Maintenance Mode columns, show the reason why it was placed into maintenance mode. Web Studio gives us this option. For example, if you place a bunch of machines, Delivery Group, or Hosting Connection into maintenance mode because you’re doing a change, just put the change number in as the reason. Then this will appear in the report.
  • Show a warning when the MCS Master Image is more than 90 days old to ensure patching cycles are not breached.

As always, I get carried away! I can’t help myself, as I love this stuff 🙂 It’s all about giving visibility to the Operations Team allowing them to stay ahead of issues and improve the service quality. Plus feedback from colleagues, like “Can you add …. ?”, didn’t help 🙂

There is a whole lot of extra data that simply just exposed in the log file output and not the HTML tables. The value for this in a future update was to generate the correct outputs for a SIEM platform or Syslog service to ingest this data. One example of this is the CrowdStrike Falcon Agent test, where is also retrieves the VDI flag.

I don’t have a lab environment big enough to provide screen shots that will provide justice to these updates. And for security and privacy reasons I’m unable to post screen shots of the reports run in a production environment without blurring out most of the data. I suggest you head over to the XenApp and XenDesktop Health Check Script GitHub repository to download and run the latest version to understand the value this will provide.

You will see that I put a lot of time and thought into these updates to provide valuable and accurate information to all that receive and review the output of this script.

By no means is it perfect, and I expect some environments may highlight aspects that need further improvement, as I am unable to test under every scenario. Please ALWAYS make sure you are using the latest version before raising an issue.

Future updates from my point of view may contain the following:

  • Change all functions to allow for Invoke-Command for PS Remoting where possible.
  • The Invoke-Command cmdlet doesn’t have a -Timeout parameter. To force a timeout for the Invoke-Command cmdlet we can put it in a ScriptBlock and run it as background job using Start-Job. Then use Wait-Job on it with -Timeout specified. It will wait the amount of time we specify and then terminate the job.
  • Look to merge the Singlesession and Multisession sections using a for loop to process, as there is quite a bit of code duplication in those two sections.
  • Look to merge the Delivery Controllers, Cloud Connectors and Storefront Servers sections using a for loop to process, as there is quite a bit of code duplication in those three sections.
  • Enhance the MCSIO tests, where possible.
  • It has been a standard practice in Citrix Consulting to set the MCSIO drive that the cache file (mcsdif.vhdx) uses to be the same size as the C drive of the image. This reduces the risk of introducing failures that can impact the business. They do this to err on the side of caution. Matching the cache disk size to image drive size ensures that it will not become a problem. We could therefore do a further test for this, by comparing the size of the drives.
  • Consider adding the Get-BrokerMachine LastAssignmentTime property as a column, which was introduced from 2209.
  • $displaymode section needs to be re-written so it uses WinRM.
  • Combine functions where possible to collect data more efficiently rather than making multiple remote connections.
  • Implement Citrix DaaS APIs (from 2209 and above) to remove reliance on PowerShell SDK. Even though Sasha has started a new Citrix Cloud Desktop as a Service (DaaS) environment checks repository I believe that the DaaS APIs can be slotted into this script quite easily with a variable to switch between them, which will allow new and legacy to work side-by-side. For reference, the Citrix PowerShell cmdlets we call in the script are:
    • Get-BrokerDBConnection
    • Get-BrokerSite
    • Get-LogLowLevelOperation
    • Get-BrokerController
    • Get-BrokerCatalog
    • Get-ProvScheme
    • Get-BrokerDesktopGroup
    • Get-BrokerMachine
    • Get-BrokerTag
    • Get-BrokerConnectionLog
    • Get-BrokerHypervisorConnection
    • Get-BrokerSession
    • Group-BrokerMachine
  • If Syslog is not enough, then further convert the output for ingestion into tools like Splunk, Azure Monitor Logs, VMware Aria Operations for Logs (formerly VMware vRealize Log Insight), OpenSearch, Elasticsearch, Cribl, etc.
  • Implement connection failures using the Odata API instead of the Get-BrokerConnectionLog cmdlet, which lacks enhanced data.
  • Citrix Cloud licensing checks will be handled by a separate script I have created, soon to be released.

Here is an exhaustive list of the bug fixes, improvements and enhancements I have completed.

Release 1.4.7:

  • Bugfix added emailCC to XML parameters file
  • Added new functions to test for connectivity: Test-Ping, IsWinRMAccessible, IsWMIAccessible, IsUNCPathAccessible
    These are fast and efficient for testing base connectivity to the machines before running each test, which helps prevent the functions from waiting for timeouts when connectivity is a problem.
  • Removed the old Ping function. There wasn’t anything wrong with it. I was just attempting to improve its efficiency.
  • Moved the $wmiOSBlock scriptblock to a function and removed the OS version check using the version of the C:\Windows\System32\hal.dll library. This is inefficient, slow and can be inaccurate as the hal.dll version loosely correlates to OS builds, but isn’t guaranteed to match OS version of edition exactly. Replaced it with the Get-OSVersion function, which also returns the caption that can be useful for other checks.
  • Added new functions for tests: Get-UpTime, Get-OSVersion, Get-NvidiaDetails, Check-NvidiaLicenseStatus, Get-RDSLicensingDetails, Get-PersonalityInfo, Get-WriteCacheDriveInfo
    These will help move the code to functions as per future improvements from version 1.5.x
  • Enhanced the following functions to allow for WinRM: CheckCpuUsage, CheckMemoryUsage, CheckHardDiskUsage
  • Fixed a bug in the CheckHardDiskUsage function so it won’t fail if an ISO is left mounted as the D: drive.
  • Added $OutputLog, $OutputHTML, $ShowStuckSessionsTable and $MaxDisconnectTimeInHours variables to XML parameters file.
  • Added new Stuck Sessions table and the logic that generates the information so you can quickly see any machines or sessions that may not look healthy.
    Some of this logic relies on the $MaxDisconnectTimeInHours variable being set correctly in the parameters XML parameters file.
    The only limitation here is that the Get-BrokerSession cmdlet does not have a tags property. So it will not support filtering against the $ExcludedTags array. Therefore, we use the Get-BrokerMachine cmdlet to filter the $AllStuckSessions collection correctly against the $ExcludedTags array.
  • Added 3 new script parameters $ParamsFile, $All and $UseRunspace so the script can be launched from a central server to health check multiple sites in parallel.
  • Added the Get-LogicalProcessorCount function for the Runspace pool.
  • Reordered and improved some of the code so that it flows in and out of the scriptblock.
  • Improved some checking on the Delivery Controllers so that it exits the scriptblock if invalid.
  • Changed the $LicWMIQuery variable to $LicQuery and enhanced the code so it can use WinRM.
  • Implemented Storefront checks from Naveen Arya‘s version of the script.
  • Added ShowStorefrontTable and StoreFrontServers variables to XML parameters file to facilitate the Storefront checks.
  • Added ShowCloudConnectorTable and CloudConnectorServers variables to XML parameters file to facilitate the Cloud Connector checks.
  • Removed $ControllerVersion -lt 7 code, as this is old and should no longer be needed in this script.
  • Added ExcludedDeliveryGroups variable to XML parameters file, as a further option to ExcludedCatalogs and ExcludedTags. Updated the Check Assignments (Delivery Group Check) with this variable. Updated the code so they all support wildcards.
  • Added more checks to ensure the first element of the ExcludedDeliveryGroups, ExcludedCatalogs and ExcludedTags arrays is not empty. This ensures the script functions as expected if the values in the XML parameters file are left empty.
  • It’s important to note that as Cloud PCs are Azure AD joined only. So if you do not have permissions to run health checks against them, it is recommended to exclude the Catalogs and/or Delivery Groups from these checks. It really just depends on your setup.
  • Improved the Get-BrokerMachine filtering for SessionSupport, so less objects are returned. This reduces processing time for the Where-Object filtering.
  • The Windows 10/11 Enterprise multi-session hosts are processed as multi-session hosts, but the RDS licensing is not relevant. So the RDS Grace period is marked as N/A and we don’t run the Get-RDSLicensingDetails function on those machines.
  • Added the HypervisorConnection table and removed the HypervisorConnectionstate from the footer. It didn’t make sense to have it there.
  • As the HTML width attribute is deprecated in HTML5 and now considered obsolete, uncommented the CSS from the writeHtmlHeader function and added “width: fit-content” to the td.
  • Have removed the $headerWidths requirement for the writeTableHeader function and from the remainder of the script.
  • Whilst we can use “white-space: nowrap” to prevent a line-break at hyphen in the HTML, this will make the table too wide. Therefore modified the writeData function to replace hyphens with a non-breaking hyphen before it writes the data to the table.
  • Removed WriteCacheSize from tables in favour of vhdxSize_inGB. It makes more sense for PVS and MCSIO.
  • Renamed MCSVDIImageOutOfDate to MCSImageOutOfDate and added this to the XenApp/RDS/Multisession host checks.
  • Added the MCSIOWriteCacheDrive variable to the XML parameters file to pass to the Get-WriteCacheDriveInfo function in line with PvsWriteCacheDrive.
  • Renamed the PvsWriteMaxSize variable to WriteCacheMaxSizeInGB in the XML parameters file, and removed the PvsWriteMaxSizeInGB variable altogether, which makes sense for both PVS, when assessing the size of the vdiskdif.vhdx file, and MCSIO, when assessing the size of the mcsdif.vhdx file. This is used against the output of the Get-WriteCacheDriveInfo function.
  • The output to the “vhdxSize_inGB” column now goes to 3 decimal points, which allows us to see the 4MB default value after a reboot. This way we know it’s all good and healthy.
  • Added the “MasterImageVMDate”, “UseFullDiskClone”, “UseWriteBackCache”, “WriteBackCacheMemSize” columns to the Check Catalog table using the Get-ProvScheme cmdlet.
  • If the MasterImageVMDate is older than 90 days, mark it as a warning as it’s missed patching cycles.
  • Check the Machine Catalog ProvisioningType that the machine belongs to is MCS before filing out the MCSImageOutOfDate column. This reduces confusion.
  • Added ShowOnlyErrorXA and ErrorXA back into the logic like ShowOnlyErrorVDI and ErrorVDI.
  • Added a new table for “ConnectionFailureOnMachine” that uses the Get-BrokerConnectionLog cmdlet.
  • Added a new variable called BrokerConnectionFailuresinHours to the XML parameters file used by the ConnectionFailureOnMachine check. If the report is run first thing in the morning, this will help see any brokering issues that occurred overnight.
  • Added a Get-BrokerTag section to create the $ActualExcludedBrokerTags and $ActualIncludedBrokerTags arrays used for filtering.
  • The script will generate 6 new arrays as it processes the Machine Catalogs, Delivery Groups and Tags: $ActualExcludedCatalogs, $ActualIncludedCatalogs, $ActualExcludedDeliveryGroups, $ActualIncludedDeliveryGroups, $ActualExcludedBrokerTags, $ActualIncludedBrokerTags
    This helps us filter out the $ExcludedCatalogs, $ExcludedDeliveryGroups, $ExcludedTags by simply using wildcards. This works well if you have naming standards for these items such as “Remote PC“, “Cloud PC“, etc.
  • Added the MaintModeReason info to the MaintMode column for the VDI (singlesession) and XenApp/RDSH (multisession) tests. This is handy if an Administrator has recorded why they have placed a machine into maintenance mode using Web Studio, such as draining the sessions, a change record, etc.
  • Removed the Get-CitrixMaintenanceInfo function as we are now calling the Get-LogLowLevelOperation cmdlet directly, but still using the methodology the Stefan Beckmann created. Will revisit PS Remoting for sections of the script in a future version. Enhanced it further so we can also get information for who placed Delivery Groups and Hypervisor Connections into maintenance mode. Added PropertyName and TargetType to the output to help with debugging.
  • Added the $MaintenanceModeActionsFromPastinDays variable to the XML parameters file. It is used for the Get-LogLowLevelOperation cmdlet so we know how far back to go to get maintenance mode actions.
  • Added the Test-OpenPort function that uses the Test-NetConnection cmdlet to test for Port 80 and 443 to the Delivery Controllers, which is needed for the PowerShell SDK. This replaces the Test-Connection cmdlet, which only sends ICMP echo request packets (pings). Not only is a ping a poor test to validate a Delivery Controller, OT environments are also typically locked down where even pings are not allowed through. This could even be further enhanced to do an XDPing to check the Broker’s Registrar service.
  • Added minor updates to the New-XMLVariables function so it’s easier to debug.
  • Added the $ExcludedStuckSessionUserAccounts variable to the XML parameters file. It is used to exclude certain sessions from the Stuck Sessions table. It supports wildcards. The purpose of this is to exclude kiosk accounts that may stay logged in for long periods of time.
  • Enhanced the Uptime VDI (single-session) and XenApp/RDSH (multi-session) tests so that they are marked as an error when Uptime is $maxUpTimeDays x 3.

Release 1.4.8:

  • Replaced the CheckCpuUsage function with the Get-CpuConfigAndUsage function. This now gets the total logical processor count, as well as number of sockets and cores per socket, which helps identify misconfigurations. It will flag a warning if there is only 1 logical processor.
  • Added LogicalProcessors, Sockets, CoresPerSocket to the tests and column outputs.
  • Added the Get-TotalPhysicalMemory function to get the total physical memory, which helps identify misconfigurations.
  • Added the TotalPhysicalMemoryinGB to the tests and column outputs. It will flag as warning if less than 4GB and an error is less than 2GB.
  • Removed the error from the XenApp/RDS (multisession) report for AvgCPU, MemUsg and drive Freespace if there is no WinRM or WMI connectivity. It makes the report look untidy.
  • For the RDS Licensing tests, LicensingType 5 and LicenseServerList Unknown should be marked as error (red). Improved the documentation for the Get-RDSLicensingDetails function.
  • Fixed up a bug when the Hypervisor Connection FaultState was marked as ERROR when empty or null.
  • Tidied up the ETD_MTU test being marked as unknown if the WinRM connection is not possible. It made the report look messy and misleading.
  • The $displaymode section needs to be re-written so it uses WinRM. However, for the moment is will only run if the machine is accessible via WMI.
  • The Ping timedout result is no longer marked as an error for the Delivery Controllers, Cloud Connectors and Storefront Servers. This just depends on your security policies and relevant firewall rules for ICMP.
  • Fixed an error in the logic so that the Cloud Connector tests and table will run when $CitrixCloudCheck variable is 1.
  • If a VDI (single-session) or XenApp/RDSH (multi-session) machine is not assigned to a Delivery Group, it will be marked as a warning.
  • Added OSCaption and OSBuild column to the Delivery Controllers, Cloud Connectors and Storefront Servers tests. This helps with OS lifecycle planning.
  • Added OSCaption column to the VDI (single-session) and XenApp/RDSH (multi-session) tests. This helps with OS lifecycle planning.
  • Added the ability to sort the VDI (single-session) and XenApp/RDSH (multi-session) tables by a specific header name. For example, you can sort by Delivery Group in ascending order, instead of hostname, which can help to identify config differences within a Delivery Group where hostnames are not contiguous or naming standards have changed over time.
  • To facilitate this have added…
  • new $SortDesktopTableByHeaderName and $SortXenAppTableByHeaderName variables to the XML parameters file.
  • a new function called writeDataSortedByHeaderName that uses the $headerToSortBy parameter that we pass the new variables to. The function contains documentation on how we convert the hashtable into a collection of key-value pairs (DictionaryEntry objects), sort it, and then store it in a new ordered dictionary before creating the output.
  • Cleaned up the outputs and error capturing as much as possible throughout the script.
  • Modified the writeTableHeader function to remove td width=’6%’, which helps better with the layout.
  • Updated all table widths to help fit all the extra data collected without looking too squashed.

Release 1.4.9:

  • Uncommented a line in the writeData function that I mistakenly left commented for testing under version 1.4.8.
  • Added an Enabled column for the Delivery Group table as requested under issue #67.
  • Added a DesktopsPowerStateUnknown column for the Delivery Group table as requested under issue #48.
    The output of Get-BrokerDesktopGroup cmdlet will not provide this, so we use the Get-BrokerMachine cmdlet with the DesktopGroupName property and further filtering using the PowerState property where it equals ‘Unknown’ and then piping that to the Measure-Object cmdlet to get the count. Anything above 0 is marked as an ERROR. The issue asked that the PowerState Unknown machines to not count as an available machine. However, that’s false logic. Machines that are registered with a PowerState of Unknown will cause issues, because sessions will still attempt to be brokered to them. They DO NOT reduce the available machines.
  • A PowerState of Unknown for machines in the VDI (single-session) or XenApp/RDSH (multi-session) tables will now be marked as ERROR.
  • If PowerState is Off, Unregistered and MCSImageOutOfDate are not marked as ERROR. Reduces unnecessary errors (red) in the report.
  • Tidied up some coding for the write cache drive detection so that it doesn’t flag as an error if N/A.
  • Renamed the LastConnect test to LastConnectionTime in the VDI (single-session) section, so the name makes more sense, and added it to the XenApp/RDSH (multi-session) table too. Changed the warning from 1 month to 30 days, and error from 3 months to 90 days. This aligns with management reporting requirements and helps to identify machines that haven’t been used in a while that may be able to be decommissioned.
  • Added a DesktopsNotUsedLast90Days column for the Delivery Group table, which helps understand at a high level if we can decommission some machines from that Delivery Group. The output of Get-BrokerDesktopGroup cmdlet will not provide this, so we use the Get-BrokerMachine cmdlet with the DesktopGroupName property and further filtering using the LastConnectionTime less than ‘-90’ days and then piping that to the Measure-Object cmdlet to get the count. Anything above 0 is marked as a WARNING.
  • Found that the output of the Test-WSMan cmdlet can give false positives, so improved the IsWinRMAccessible function to deal with that.
  • Piped the output of the Get-BrokerMachine cmdlet for the VDI (single-session) and XenApp/RDSH (multi-session) tests to Sort-Object via DNSName so that there is an order to the processing and logs for anyone that may be observing it.

Release 1.5.0:

  • Added a new function called Get-ProfileAndUserEnvironmentManagementServiceStatus, which gets the status of the Citrix UPM, WEM and Microsoft FSLogix services. It checks if the services are installed, running and enabled.
  • Added the UPMEnabled, FSLogixEnabled and WEMEnabled columns and tests to the tables.
  • Added the Spooler and CitrixPrint columns and tests to the VDI (single-session) table.
  • Added an IPv4Address column to all tests to help easily identify which subnets machines are on, which also helps to locate common DHCP, firewall and routing issues.
  • Fixed a bug with the date format for the MasterImageVMDate so that it compares accurately for the 90 day warning.
  • Found that he Get-ProvScheme MachineProfile and WindowsActivationType properties can return null and throw an error, so wrapped them in a try/catch to manage this.
  • Changed the way the scriptblock can be executed locally and via Invoke-Command so that we can pass an object as a named parameter in the arguments. This needed to be enhanced so that an object can be passed into the runspace as well.
  • Improved the order of the headers and grouped them so they can easily be excluded or commented out when not required. An enhancement can be to add more variables to the XML parameters parameters file for this.

Release 1.5.1:

  • If the machine name is ghosted, don’t lookup it’s IP address. An empty variable passed to the Dns.GetHostAddresses method will lookup the IP Address of the host the script is running on, which is of course incorrect. Also wrapped some further error checking around the Dns.GetHostAddresses method.
  • Removed the pipe to Select-Object from the Get-Brokerhypervisorconnection cmdlet. This adds unnecessary processing.
  • Further improved the Citrix UPM, WEM and Microsoft FSLogix outout.
  • Further improved the Nvidia output and fixed a bug with the $returnLicensable_Product needed to be $return.Licensable_Product.
  • Improved the Citrix Cloud auth process and output.
  • Improved some documentation and log outputs.
  • Added an XDPing test for the Delivery Controller and Cloud Connector checks. It was an obvious test for Delivery Controllers. Even though Rendezvous V2 allows Cloud Connector-less direct VDA registration, standard AD domain joined machines still require Cloud Connectors for VDA registration and session brokering. Even overcoming this, Cloud Connectors may continue to be required for legacy VDA registration. And therefore should still perform an XDPing to check the health status of the CdsController Iregistrar service.
  • Changed the EDT MTU test so that it doesn’t flag as failed if no data is returned from the “C:\Program Files (x86)\Citrix\HDX\bin\CtxSession.exe” command. That is misleading.

Release 1.5.2:

  • Updated the Citrix Cloud (DaaS) authentication process allowing for the change in the way the AdminAddress (AKA XDSDKProxy) has been removed as a Global variable and now stored in as a key/value pair under the NonPersistentMetadata property of the Get-XDCredentials cmdlet output. Refer to my article here.
  • Updated the Check-NvidiaLicenseStatus to use a switch statement instead of an if/else block. Improved the logic and outputs to help track common issues when licensing fails.
  • Added the Get-CrowdStrikeServiceStatus function to check and audit CrowdStrike Windows Sensor information.
  • Added the CSEnabled and CSGroupTags columns to the tables. CSEnabled means that CrowdStrike is installed and running with an Agent ID. CSGroupTags are the Sensor group tags used when installed. This gives us a nice way to audit where it’s missing and which tags have been used to ensure we have consistency. This relies on WinRM being enabled across all hosts.
  • Added the $ShowCrowdStrikeTests variable to the XML file.
  • Updated the XDPing function.

Release 1.5.3:

  • Updated the documentation in the IsWinRMAccessible function. This can be used to demonstrate to the Cyber team that WinRM will use Kerberos authentication and is encrypted, despite using the default HTTP port of TCP 5985. The WinRM tests will only proceed if this function returns true.
  • Further enhanced the XDPing function.
  • Added an Unassigned column to the MachineCatalogs table, and a test for the AvailableUnassignedCount, which is the number of available machines (those not in any desktop group) that are not assigned to users. It is marked as a warning if great than 0.
  • Fixed 2 bugs with the Get-CrowdStrikeServiceStatus function.
  • More coding tidy-ups to provide improved output.

Release 1.5.4:

  • Improved both the Get-ProfileAndUserEnvironmentManagementServiceStatus and Get-CrowdStrikeServiceStatus functions by making them more resilient.
  • Fixed a bug with the ToHumanReadable function where it would error if uptime was less than 1 hour.
  • If the multisession or singlesession host uptime is less than 1 day, output to the log is in human readable format. This makes it easier to find how many hours or minutes ago it last rebooted.

Release 1.5.5:

  • Fixed a bug in the Citrix Cloud Auth related to the NonPersistentMetadata property not existing with older PowerShell modules. Basically just wrapped some more error checking around it using a Try/Catch.

Release 1.5.6:

  • Added XML variable MarkSpoolerAsWarningOnly. This can be used to flag a failed Spooler and CitrixPrint service as a warning only. It reduces the red (errors) in the reports in environments where these services are not required for normal operation.
  • For multi-session hosts, if ActiveSessions is greater than ConnectedUsers count, mark as an error. It should point to a ghosted session in the Stuck Sessions Table. Depending on the size of your environment and the potential time difference between when the multi-session host test collects data via the Get-BrokerMachine cmdlet and the stuck sessions collects data via the Get-BrokerSession cmdlet, the ghosted sessions may have cleared, and that discrepancy is no longer valid.
  • Fixed a bug with the ActiveSessions Count property if the System.String[] (an array of strings) object has been cast into a System.String.
  • Added XML variable SupportedVDAVersions. Any versions that do not match will be marked as a warning in the VDAVersion column and log. Leave the setting empty in the XML to ignore
    this. This helps with planning for software lifecycle management and to flag when someone has deployed an unsupported version.
  • Updated the Citrix Cloud Auth related code to expose the bearer token in a variable which can be used in the header for OData API Authorization.
  • Improved the Get-PersonalityInfo function to test for more scenarios based on the history of VDA changes for the Personality.ini and MCSPersonality.ini files.
  • Improved the logging for CrowdStrike output.
  • Added a minor code improvement to the Get-WriteCacheDriveInfo function.
  • Extended the use of the $ErrorVDI and $ErrorXA variables to flag the machine for all warnings and errors.
  • Added new functions ConvertTo-StructuredData and Write-IetfSyslogEntry for Syslog output.
  • Added XML variables CheckOutputSyslog, OutputSyslog, PrivateEnterpriseNumber, StructuredDataIDPrefix, SyslogMsgId, SyslogFileOnly, SyslogServer to support Syslog output.
  • Added new script variables $SyslogAppName, $StructuredDataID and $resultsSyslog to support Syslog output, which are derived from XML variables.
  • Added the $IsSeverityWarningLevel and $IsSeverityErrorLevel script variables throughout the test sections of the script to support the Severity level for Syslog.
  • Added the Get-CCSiteId function to get the Citrix Cloud Site Id, which can then be appended to the “cloudsite” name. The SiteName is then added to each test to provide uniqueness across sites when bringing the data altogether into observability platforms.
  • Added the $AppendCCSiteIdToName XML variable. The Site Name for Citrix Cloud is “cloudxdsite”. If you are running checks against multiple Citrix Cloud sites, you may want to set this to true to append the SiteId GUID for uniqueness.
  • Also added the Get-BearerToken and Get-CCSiteDetails functions in preparation for leveraging the APIs.
  • Fixed a bug with the getting site maintenance information using the Get-LogLowLevelOperation, where it may not return all records.
  • Added the $NoProxy and $SkipCertificateCheck XML variables, which make it easier when working with the Invoke-RestMethod and Invoke-WebRequest cmdlets.
  • Added further variables to the XML params file to support the new Logon Durations script called CitrixLogonDurations.ps1 that I will publish separately. This allows them to share the same XML params files, avoiding duplication.

Release 1.5.7:

  • Added the Get-CCOrchestrationStatus function in preparation for leveraging the APIs. Using it initially to get the ProductVersion.
  • Added further variables to the XML params file to support the new Failed Connections script called CitrixFailedConnections.ps1 that I will publish separately. This allows them to share the same XML params files, avoiding duplication.
  • Added XML variable ShowBrokerConnectionFailuresTable to disable the Connection Failure On Machine table. Using the output from the CitrixFailedConnections.ps1 script provides an improved and thorough output aligned with Citrix Director.

Release 1.5.8:

  • Enhanced the Get-WriteCacheDriveInfo function by also allowing for the CacheDisk label from BISF and WRcache label used by another community member.
  • Fixed a bug with the output of the Get-ProfileAndUserEnvironmentManagementServiceStatus function.
  • Added the RDSGracePeriodExpired column to the XenApp/RDS/Multisession host table.
  • Added the Get-RDLicenseGracePeriodEventErrorsSinceBoot function to populate the test for RDSGracePeriodExpired, which is done via the Event Log. This will provide more accuracy than the GetGracePeriodDays method from the Get-RDSLicensingDetails function. If RDSGracePeriodExpired is True, RDSGracePeriod is marked as error to remove confusion.
  • Enhanced the Check-NvidiaLicenseStatus function to allow for “Platform detection successful” to check if it is licensed in Azure. When using specific Azure N-series VMs you do not need a separate NVIDIA vGPU license server. The necessary licensing for the NVIDIA GRID software is included with the Azure service itself. Microsoft redistributes the Azure-optimized NVIDIA GRID drivers which are pre-licensed for the GRID Virtual GPU Software in the Azure environment. The “Platform detection successful” message indicates that the NVIDIA driver has correctly recognized it is running on a the supported Microsoft Azure virtual machine instance where a license is automatically provide through the platform.
  • Enhanced the Get-RDLicenseGracePeriodEventErrorsSinceBoot function to wrap the Invoke-Command cmdlet in a Start-Job cmdlet so we can use a timeout. This will help to prevent the Invoke-Command cmdlet getting stuck on unhealthy remote machines.
  • Added RecommendedMinimumFunctionalLevel to both the DeliveryGroups and Catalogs tables and enhanced the code under the DeliveryGroups and Catalogs Check to derive the recommended MinimumFunctionalLevel based on VDA Agent Versions in the Delivery Group and Machine Catalog respectively. This required adding the $ProductVersionValues table and $ProductVersionHashTable hashtable that provides a mapping between the Marketing Product Version, Internal Product Version, and the MinimumFunctionalLevel used by the Delivery Groups and Machine Catalogs. Used the Group-BrokerMachine cmdlet to help achieve this.
    Added the Find-CitrixVersion, Convert-ToComparableVersion, Convert-FunctionalLevelToVersion and Convert-VersionToFunctionalLevel functions so that we can:
    1) Get the Internal Product Version and MinimumFunctionalLevel based on the Marketing Product Version
    2) Get the Marketing Product Version and MinimumFunctionalLevel based on the Internal Product Version
    3) Get the Lowest Supported VDA Version based on the MinimumFunctionalLevel and the Highest VDA Version Before the Next FunctionalLevel
    4) Convert the MinimumFunctionalLevel to a version for comparison, and back again for correct output.
  • Added MachinesInMaintMode and PercentageOfMachinesInMaintMode to the DeliveryGroups table and enhanced the code under the DeliveryGroups Check to get the count and percentage of machines in maintenance mode and mark as warning if greater than 0% and error if 50% or greater. This will help alert Admins to potential issues when accidentally placing too many machines into maintenance mode, or simply forgetting to remove maintenance mode after a maintenance task and/or a reboot. Used the Group-BrokerMachine cmdlet to help achieve this.
  • If using an on-prem License server and the output for the license table contains no data, it will be excluded from the HTML report. This may be because it is License Activation Service (LAS) enabled. With LAS enabled we now have unlimited capacity and no way to get a license count. “LAS provides products with unlimited capacity for the duration of the entitlement validity. Because LAS does not require a ‘check-out’ operation to track individual licenses, real-time usage metrics are not available within the License Server or Citrix Cloud.”
    A reference to the “Unlimited capacity” point here: https://docs.citrix.com/en-us/licensing/current-release/license-activation-service.html
  • Added further variables to the XML params file to support the new Insights script called CitrixInsights.ps1 that I will publish separately. This allows them to share the same XML params files, avoiding duplication.

Release 1.5.9:

  • Added LicenseEdition and LicenseModel to the footer table for on-prem CVAD deployments.
  • Improved the code so that if the VDA Agent Versions for Machine Catalog and Delivery Group cannot be found in the ProductVersionValues table, it reports that it is unable to determine the RecommendedMinimumFunctionalLevel. This prevents misleading results and advises that the ProductVersionValues table needs to be updated in order to achieve a valid outcome.
  • Added the IgnoreExclusions parameter which makes it easy to run a full report that includes machines across all Machines Catalogs and Delivery Groups, also ignoring Tags, preventing the need to modify the XML params files just to achieve this outcome.
  • Fixed a bug in the log output for the NVidia license check where it would log an error for “nvidiaLicense: Platform detection successful”.
  • Fixed a bug with the Get-RDLicenseGracePeriodEventErrorsSinceBoot function that would cause it to fail if the “Microsoft-Windows-TerminalServices-RemoteConnectionManager/Admin” Event Log cannot be found.

Enjoy!

Jeremy Saunders

Jeremy Saunders

Delivering customer success through tech: IT Infrastructure | Citrix | End User Computing | Platform Engineering | DevOps | Full Stack Developer | Technical Architect | Improvisor | Aspiring Comedian | Midlife Adventurer at J House Consulting
Jeremy Saunders is the Problem Terminator; the MacGyver of IT. Views and Intellectual Property (IP) published on this site belong to Jeremy. Please refer to the About page for more information about Jeremy.