Skip to content
Home » VMware Horizon – Powershell scripting (Desktop Pools)

VMware Horizon – Powershell scripting (Desktop Pools)



Today we’ll be monitoring our desktop pools. In our PRTG monitoring, we’d like to see the status of our desktop pools, the status of the provisioning and of course if there are enough desktops available.

Desktop Pools

A desktop pool can be enabled or disabled, so we’d like to see that in our PRTG monitoring system. Also provisioning can be enabled or disabled foor a VDI desktop pool, but not for a Remote Desktop Session Host pool, so we’ll have to catch this. To get the usage data of the desktop pool, we’ll retrieve the number of machines that are configured on the desktop pool and also the number of the current sessions (active or disconnected) of the desktop pool.

We will use the QueryService again, as we did in the previous post for the Problem VM’s. This time we’ll query the entity “DesktopSummaryView”. This will give us all the desktop pools and their data.

 ...
    $query_Service = New-Object "Vmware.Hv.QueryServiceService"
    $query = New-Object "Vmware.Hv.QueryDefinition"
    $query.QueryEntityType = 'DesktopSummaryView'
    $Pools = $query_Service.QueryService_Query($viewAPI,$query)

    foreach($dp in $Pools.Results)
    {
        if ($dp.DesktopSummaryData.Name -eq $HVPoolID)
        {
            if ($dp.DesktopSummaryData.Type -ne "RDS")
            # no usage calculation for RDS types
            {
                $usage = $dp.DesktopSummaryData.NumSessions / $dp.DesktopSummaryData.NumMachines * 100
            }
                        
            # Current sessions (active & disconnected)
            $dp.DesktopSummaryData.NumSessions

            # total number of VDI machines (for RDSH this is the total number of RDSH Servers)
            $dp.DesktopSummaryData.NumMachines

            # Status of the desktop pool
            $dp.DesktopSummaryData.Enabled

            if ($dp.DesktopSummaryData.Type -ne "RDS")
            # Provisioning is disabled for RDS type
            {
                $dp.DesktopSummaryData.ProvisioningEnabled
            }

            # Only RDSH pools
            if ($dp.DesktopSummaryData.Type -eq "RDS")
            {
                # match RDS Id with RDSServerSummaryView to get status of RDS servers in farm
                # used to detect if RDS server availability status
                $query_Service2 = New-Object "Vmware.Hv.QueryServiceService"
                $query2 = New-Object "Vmware.Hv.QueryDefinition"
                $query2.QueryEntityType = 'RDSServerSummaryView'
                $filter2 = new-object VMware.Hv.QueryFilterEquals -Property @{'memberName' = 'base.desktop'; 'value' = $dp.Id}
                $query2.Filter=$filter2
                
                $Farms = $query_Service2.QueryService_Query($viewAPI,$query2)
                
                # only retrieve first RDSH server from the result
                $Farms.Results[0].RuntimeData.Status
            }
        }
    }
...

Because we want to have a separate sensor in PRTG for each of our desktop pools, we’ll use an extra filter to call the script so we only return data for one specific desktop pool. Some of the data is not applicable to RDSH pools, like provisioning and total number of machines, so we’ll have to check this too.

For each desktop pool we’ll retrieve the data from the DesktopSummaryData property. In the DesktopSummaryData.Type we’ll see if it’s and RDSH server (value: “RDS”) or not (value: “AUTOMATED” or “MANUAL”).
In the DesktopSummaryData.numMachines & .numSessions we’ll find the total number of VDI machines and the number of active or disconnected sessions. We’ll use this to calculage the usage percentage.

As we don’t have provisioning status on the RDSH desktop pools, we’ll need to create a second QueryServiceService to retrieve the RDSServerSummaryView. In this object we can find the status of the RDS Server. I’m only checking the status for the value “AVAILABLE”. Any other status will show as “not available” in PRTG. Check the VMware {code} site for the other statuses.

If we wrap this all up and format the result in a correct PRTG XML format this becomes the complete script:

param (
    [string]$HVServer="connectionserver.horizon.test",
    [string]$HVUser,
    [string]$HVPass,
    [string]$HVPoolID = ""
)

if ($HVPoolID -ne "")
{
    Import-Module VMware.VimAutomation.Core
    Import-Module VMware.VimAutomation.HorizonView
    if ($HVUser -eq "" -or $HVPass -eq "") { $con = Connect-HVServer -Server $HVServer  }
    else { $con = Connect-HVServer -Server $HVServer -User $HVUser -Password $HVPass }
    $viewAPI = $con.ExtensionData
    $query_Service = New-Object "Vmware.Hv.QueryServiceService"
    $query = New-Object "Vmware.Hv.QueryDefinition"
    $query.QueryEntityType = 'DesktopSummaryView'
    $Pools = $query_Service.QueryService_Query($viewAPI,$query)
    write-host "<prtg>"
    foreach($dp in $Pools.Results)
    {
        if ($dp.DesktopSummaryData.Name -eq $HVPoolID)
        {
            if ($dp.DesktopSummaryData.Type -ne "RDS")
            # no usage calculation for RDS types
            {
                $usage = $dp.DesktopSummaryData.NumSessions / $dp.DesktopSummaryData.NumMachines * 100
                write-host "  <result>"
                write-host "    <channel>Usage</channel>"
                write-host "    <value>$usage</value>"
                write-host "    <unit>percent</unit>"
                write-host "    <float>1</float>"
                write-host "    <DecimalMode>Auto</DecimalMode>"
                write-host "    <limitMode>1</limitMode>"
                write-host "    <LimitMaxWarning>85</LimitMaxWarning>"
                write-host "    <LimitMaxError>95</LimitMaxError>"
                write-host "  </result>"
            }
                        
            write-host "  <result>"
            write-host "    <channel>$($dp.DesktopSummaryData.Name) Sessions</channel>"
            write-host "    <value>$($dp.DesktopSummaryData.NumSessions)</value>"
            write-host "    <unit>count</unit>"
            write-host "  </result>"

            write-host "  <result>"
            write-host "    <channel>$($dp.DesktopSummaryData.Name) Machines</channel>"
            write-host "    <value>$($dp.DesktopSummaryData.NumMachines)</value>"
            write-host "    <unit>count</unit>"
            write-host "  </result>"

            write-host "  <result>"
            write-host "    <channel>Desktop Enabled</channel>"
            if ($dp.DesktopSummaryData.Enabled) {write-host "    <value>1</value>"} else{write-host "    <value>2</value>"}
            write-host "    <unit>Custom</unit>"
            write-host "    <ValueLookup>prtg.standardlookups.yesno.stateyesok</ValueLookup>"
            write-host "  </result>"

            if ($dp.DesktopSummaryData.Type -ne "RDS")
            # Provisioning is disabled for RDS type
            {
                write-host "  <result>"
                write-host "    <channel>Provisioning Enabled</channel>"
                if ($dp.DesktopSummaryData.ProvisioningEnabled) {write-host "    <value>1</value>"} else{write-host "    <value>2</value>"}
                write-host "    <unit>Custom</unit>"
                write-host "    <ValueLookup>prtg.standardlookups.yesno.stateyesok</ValueLookup>"
                write-host "  </result>"
            }

            if ($dp.DesktopSummaryData.Type -eq "RDS")
            {
                # match RDS Id with RDSServerSummaryView to get status of RDS servers in farm
                # used to detect if RDS server agent unreachable status
                $query_Service2 = New-Object "Vmware.Hv.QueryServiceService"
                $query2 = New-Object "Vmware.Hv.QueryDefinition"
                $query2.QueryEntityType = 'RDSServerSummaryView'
                $filter2 = new-object VMware.Hv.QueryFilterEquals -Property @{'memberName' = 'base.desktop'; 'value' = $dp.Id}
                $query2.Filter=$filter2
                
                $Farms = $query_Service2.QueryService_Query($viewAPI,$query2)
                
                write-host "  <result>"
                write-host "    <channel>Status</channel>"
                if ($Farms.Results[0].RuntimeData.Status -eq "AVAILABLE") {write-host "    <value>1</value>"}
                else { write-host "    <value>0</value>"}
                write-host "    <unit>Custom</unit>"
                write-host "    <ValueLookup>prtg.standardlookups.offon.stateonok</ValueLookup>"
                write-host "  </result>"
            }
        }
    }
    write-host "</prtg>"

    # disconnect from our connection server
    $con | Disconnect-HVServer -Force -Confirm:$false
}

PRTG

When we create a new “EXE/Script advanced” sensor pointing to our script above (see the previous post on how to create the sensor), We’ll get the follwing information:

So we have a channel for the current sessions of a desktop pool, a total number of provisioned machines, a calculated value that gives us the usage percentage (e.g. 50% available desktops in use). We also have status indicators showing us if the desktop pool is enabled and if provisioning is enabled.

Optimization

This was one of my first scripts I wrote to monitor our VMware Horizon environment. While writing this blog post, I see there’s room for improvement in this script. For example in stead of looping through the results of all desktop pools, I could also create a filter on the initial query. Once I have some spare time to optimize this script, I’ll update it here.

This concludes our latest post about monitoring our VMware Horizon environment with PRTG. Stay tuned for more to come!



5 thoughts on “VMware Horizon – Powershell scripting (Desktop Pools)”

  1. This is an awesome script, thank you for putting these together. I am having an issue maybe you could help with? Horizon 8 environment, when I run the script from ISE I receive the expected output in the xml format in the view window. However, I set up the sensor in PRTG according to your instructions, when viewing the log file in Program Data “Result of Sensor XXXX” all the file contains is – of course in PRTG the error is no result.. I have checked execution policy and made sure the module was accessible to all users. Thanks for any input you can provide.

    1. Hi, Have you tried running the script as the user which is running PRTG?
      Is it the only script that is giving “no result” or do you have others behaving the same?

      1. I did notice that in the log late yesterday. It was attempting to login as the prtg service account which did not have the appropriate permissions in view to pull the data. Event log also logged a “400 error” that correlates with the time of the log entry. I also did not notice in the params defined in the sensor HVServer %host was sending the host info of the PRTG VM across. I corrected that entry as well. This allowed the sensor to pull back the expected data. Thank you for replying, I just wanted to make sure I put this here for others to see if needed.

    1. Hi James, sorry to hear that. Can you give some more information of where it goes wrong? What version of Horizon are you using? Error messages? etc…

Leave a Reply

Your email address will not be published. Required fields are marked *