Menu Close

Move AVD session hosts to a new host pool with REST API

Last updated 3 months ago by Sander Rozemuller

Azure Virtual Desktop is growing and becomes available at new (metadata) locations more and more. In this article I will explain how to move AVD session hosts to a new AVD host pool. metadata location with REST API and PowerShell.

Introduction

Azure Virtual Desktop is a relative new Azure service. This new service will take care of publishing a remote working place. The working place with its resources is for your own responsibility but Microsoft will take care of the session handling, the login website and publishing the correct work spaces to end users.
The Microsoft-part also has stored his configuration somewhere. This location is called the metadata location. As mentioned AVD is a quiet new Azure service where the metadata locations are growing. In the early beginning only metadata location available was the US.

Now more the a year later there are a lot more metadata locations and are still growing. This is good news, but only for new AVD host pools. At this moment there is no option moving a host pool to a new metadata location. Luckily we are able to create a new host pool and then move existing session hosts to the new host pool. In this article I will show you how to move the session hosts to a new host pool automated.

Table of Contents

AVD metadata locations

Azure Virtual Desktop consists of several Azure Resources. Think of the session hosts (virtual machines), networking, file servers or other associated services. An another part of AVD are services resources. Think about the the session broker, a gateway and the web page.

In the graph below you see the three big Azure Virtual Desktop pieces. The most right resources are the customers responsibility. This resources can be stored at every Azure geographical location. This are the resources which are at your own responsibility.

The middle part are the AVD services resources. This resources are managed by Microsoft and also stored somewhere. That location is called the metadata location. At this location Microsoft stores information about traffic patterns, health checks, usage log and more. This information is needed to control the infrastructure can scale capacity if needed. Customer data is not stored at this location.

Currently Microsoft has the following locations available.

  • United States (US) (generally available)
  • Europe (EU) (generally available)
  • United Kingdom (UK) (generally available)
  • Canada (CA) (generally available)

More information about data location please check the AVD data location documentation.

Move AVD session hosts to an another host pool

Microsoft is planning more locations in future. That will make is possible to get the metadata location at a place you like. However at this moment it is not possible to move a host pool to a new location. Even when you move the host pool to a new resource group, with an another location, the host pool location will not be changed.

But there are options to change the metadata location if you like. There is an option to move session hosts to a new host pool. This can be done by creating a new host pool at the correct location and moving the session hosts to the new host pool.

In the following chapters I will explain the process how to move an AVD session host to a new host pool with REST API.

In my situation I have two AVD host pools:

  • Rozemuller-Hostpool located in West-Europe
  • US-Hostpool located in East-US.

The Rozemuller-Hostpool has one session host wvd-0.rozemuller.local. The US-Hostpool is empty.

Remove session host from AVD host pool

The first step in the process is removing the session host from its current host pool. Make sure there are no sessions associated with the host. Otherwise you will get an error message like below.

Once the session host is empty you are able to remove it from the host pool. We are using the REST API for removing the session host.

Authenticating

Before you are able to use the REST API you will need to authenticate to the API.
Because we are using PowerShell for executing the REST API calls we only need to authenticate in PowerShell. From that context we are gathering a header token for the REST API.

function GetAuthToken($resource) {
    $context = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext
    $Token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $resource).AccessToken
    $authHeader = @{
        'Content-Type' = 'application/json'
        Authorization  = 'Bearer ' + $Token
    }
    return $authHeader
}
$token = GetAuthToken -resource "https://management.azure.com"

The authentication token will returned into the $token variable. This is the token we need for requesting API calls to Azure.

Remove session host

If we have received a token we are able to call the REST API for removing the session host. I will save the outcome into the $DeleteSessionHost variable. The command returns the session host object. The object contains the virtual machine resourceId which is needed in the next step.

$ResourceGroupName = "rg-wvd-001"
$hostpoolname = "Rozemuller-hostpool"
$SessionHostName = 'wvd-0.rozemuller.local'

$SessionHostUrl = "https://management.azure.com/subscriptions/" + $script:subscriptionId + "/resourceGroups/" + $ResourceGroupName + "/providers/Microsoft.DesktopVirtualization/hostpools/" + $HostpoolName + "/sessionHosts/" + $sessionHostName + "?api-version=2021-03-09-preview"
$parameters = @{
    uri     = $SessionHostUrl
    Method  = "DELETE"
    Headers = $token
}
$sessionHost = Invoke-RestMethod @parameters

The Rozemuller-Hostpool is now empty.

Generate token

A session host will register itself to a host pool with a globally unique token. This very long string in combination with the host pool name will make it possible to join a host pool. The AVD RD Infra Agent will search in the Azure cloud for a host pool name with this token and register itself into that host pool.

A token must be available between an hour and a maximum of 27 days.

In my code I will generate a new token for 1 hour in the new host pool. This for the simple reason I don’t need more time to register the session host. Make a notice about the $hostpoolToken variable. I will store the output into this variable. I need the token which will returned.

$NewResourceGroupName = "rg-wvd-001"
$Newhostpoolname = "US-Hostpool"
$baseUrl = "https://management.azure.com/subscriptions/" + $script:subscriptionId + "/resourceGroups/" + $NewResourceGroupName + "/providers/Microsoft.DesktopVirtualization/hostpools/" + $Newhostpoolname + "?api-version=2021-03-09-preview"
$Body = @{
  properties = @{
      registrationInfo = @{
        expirationTime = "$($(Get-Date).AddHours(1))"
        registrationTokenOperation = "Update"
      }
  }
}
$parameters = @{
    URI     = $baseUrl 
    Method  = "PATCH"
    Headers = $token
    Body = $Body | ConvertTo-Json
}
$hostpoolToken = Invoke-RestMethod @parameters

Use the code below in the next request body.

$hostpoolToken.properties.registrationInfo.token

Add session host to a new AVD host pool

The last step generating a script which will executed on the session host. We have stored the session host Id and the token in variables and are using these in the body.

We are also going to send an invoke-azruncommand via the REST API. To send a script via the REST API we need to generate an arraylist with PowerShell. In the first part of the commands below we are creating an arraylist and add commands with the .Add () function.

In the first command I use the $hostpool token variable which is the registrationToken value in the registry.
The $sessionHost resource Id is used in the REST API url.

$script = [System.Collections.ArrayList]@()
$script.Add('Set-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\RDInfraAgent -Name RegistrationToken -Value '+$($hostpoolToken.properties.registrationInfo.token)+'')
$script.Add('Set-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\RDInfraAgent -Name IsRegistered -Value 0')
$script.Add('Restart-Service -Name RDAgentBootLoader')

$MoveBody = @{
    commandId = "RunPowerShellScript"
    script    = $script
}
$url = "https://management.azure.com" + $($sessionHost.properties.resourceId) + "/runCommand?api-version=2021-03-01"
$parameters = @{
    URI     = $url 
    Method  = "POST"
    Body    = $MoveBody | ConvertTo-Json
    Headers = $token
}
Invoke-RestMethod @parameters

Wait for a few minutes after running the command. Look at the new host pool and see the session host is moved to a new host pool.

PowerShell Module Az.Avd

If you are not that familiar with Rest API, no worries. I also updated the Az.Avd PowerShell module with a new command called Move-AvdSessionHost. This command helps you moving session hosts to an other host pool.

Thank you for reading about moving AVD session hosts to a new host pool via REST API.
Take care and happy automating. Enjoy your day and happy automating 👋

1 Comment

  1. Tom Hickling

    Great article. Just one small correction just for clarity. In the AVD metadata locations section you mention that the middle section of the 3 big pieces diagram is stored in the metadata locations. So, this isn’t strictly true. There are actually 4 big pieces, including the AVD control plane (middle section) and the metadata service. The control plane and metadata service are separate services not to be confused.
    The AVD control plane – the middle part of the diagram is actually located in over 30 specific Azure regions globally. The 4th piece is the metadata service. The metadata is today only stored in those 4 Azure “geographies” you mention. Note we don’t specify the actual Azure regions the metadata is stored in just the higher level geo. Some of those 30+ Azure regions that host he AVD control plane will be the same regions that host the metadata however. Hopefully this explains it in more detail: https://docs.microsoft.com/en-us/azure/virtual-desktop/data-locations

Leave a Reply

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