Directly connect session hosts with a 3rd party management environment

While working with Azure Virtual Desktop, I still miss some features that seem unavailable through Microsoft or maybe a 3rd party vendor. One of the features is that an admin/helpdesk can see the users’ processes, CPU, and memory usage and terminate a hanging or crazy process. To build this feature, a fast connection to the session host from the management platform (in my case, Hydra) is needed. The approach using the RunCommandExtension is not fast enough and doesn’t allow duplex communication.

While web-based management platforms normally do not have a direct IP connection to the session hosts, the typical remote administration approaches won’t work. Therefore, I see no other way to have a small agent running on the session hosts connecting to the web-based management platform. One approach is that the agents connect via https to the management platform - the better way is using Web-Sockets to connect. Websockets (WS) are faster and scale better than sending an http-request each second from each host to the platform. WS also directly supports a communication strategy.

In the preview version of Hydra, the agents connect securely (via a secret) to the platform and identify themselves via the FQDN and VM resource Id. That allows being referenced as a session host as well.

In my case, only the platform can ask the client (session host). For that, I build several classes. In each case, the platform asked a specific client for information (GetProcessList for session “2”), and the client response after a short time with the data (SetProcessList and SessionHostProcess[] as JSON in the content property).

For this example, asking for the process list is initiated by a management platform admin with the right permissions. The admin can also initiate a kill process to stop a process. While this works fast, the process list can be refreshed every few seconds automatically and shown on the website of the management platform.

The fast communication between the platform and session hosts allows additional or improved features:

  • Showing CPU/MEM per session host faster than using the Azure API (Azure agent)

  • A general fast monitoring

  • De-prioritized processes

  • Fast chat with the user

  • Improve scaling: Avoid logging off a disconnected session if a particular application is running (Excel, SAP - may be based on the CPU usage)

  • Improve scaling: Avoid logoff VIP users

  • Get more data from the native AD via this connection

  • Join computer objects fast into groups in a native AD

  • Trigger a garbage collector

  • Running scripts on the hosts - concurrently with duplex communication (to show a now written log file)

  • Configure application

  • Get data about FSLogix issues

  • Get data about FSLogix disk sizes

Using WS makes a solution more flexible and avoids the limits of the RunCommandAPI. The price for this is another agent (not a service), which must be deployed during the rollout or afterward. From the first researches and implementation, there is no low limit regarding the number of hosts.

The current version of Hydra has the preview feature (to be released) showing the process list if an admin clicks on the user name in the session list. While this feature is in preview, test users must ask to switch on this feature for a specific Hydra instance). Check out the video on YouTube: https://youtu.be/aNiNbEukVVc

The final question: Are the features worth that an agent is needed?

Update from 4/1/2022: Using an agent would be perfect to manage Windows 365 as well. W365 is missing some API to work directly with the VM (like the RunCommandAPI). An agent would solve the missing APIs and would allows to manage W365 users and hosts with some features mentioned above.

First classes for the duplex-communication:

public class Communication
  {
​    public CommunicationType Type { get; set; }
​    public string Content { get; set; }
  }

public enum CommunicationType
  {
​    GetHostIdentifier,
​    SetHostIdentifier,
​    GetProcessList,
​    SetProcessList,
​	KillProcess,
  }

public class HostIdentifier
  {
​    public string SessionHostResourceId { get; set; }
  }

public class SessionHostProcess
  { 
​    public int ProcesId { get; set; }
​    public string  Caption{ get; set; }
​    public int SessionId { get; set; }
​    public long WorkingSet { get; set; }
​    public double CpuPercent{ get; set; }
  }