Forum Discussion
Update to Microsoft Desktop Virtualization API v. 2023-09-05 by August 2, 2024 to avoid any impact
[Recommended actions updated on July 29, 2024]
WARNING! Be mindful when using secrets in deployment templates and follow Azure best practices when managing secrets. Our examples in this discussion post are to be used for educational purposes only. |
Older Microsoft Desktop Virtualization API version(s) utilized for your Azure Virtual Desktop host pool resource will no longer support ‘get’ actions for registration token retrieval as of August 2nd, 2024.
The affected API versions are as follows:
- 2019-01-23-preview
- 2019-09-24-preview
- 2019-12-10-preview
- 2020-09-21-preview
- 2020-11-02-preview
- 2020-11-10-preview
- 2021-01-14-preview
On August 2nd, 2024, these affected API versions will no longer support the retrieval of the registration token. Users on older versions will not be able to use the 'get' action to retrieve the token. However, with the newer versions, there are two ways for customers to retrieve registration tokens moving forward:
- [Recommended] Using list* resource functions: Microsoft.DesktopVirtualization/hostpools resources now expose a listRegistrationTokens() function. This works if you already have valid registration tokens on your host pool and you want to retrieve them from an existing host pool.
- Using a 'post' action to securely retrieve the token
- AZ CLI: az desktopvirtualization hostpool retrieve-registration-token - az desktopvirtualization hostpool | Microsoft Learn
- REST: Host Pools - Retrieve Registration Token - REST API (Azure Desktop Virtualization) | Microsoft Learn
- AZ PowerShell: Get-AzWvdHostPoolRegistrationToken (Az.DesktopVirtualization) | Microsoft Learn
Action Required
- Review any workflows you may have that rely on readers retrieving access tokens and update them to extract the registration tokens for a host pool in a new way.
- Ensure you are using up to date versions of the Microsoft Desktop Virtualization API.
To take action, here are examples of how to extract the registration tokens for a host pool and update to the 2023-09-05 API version using Bicep and ARM templates.
WARNING! Be mindful when using secrets in deployment templates and follow Azure best practices when managing secrets. Our examples in this discussion post are to be used for educational purposes only. |
[Recommended] Take action using list* resource functions
This solution works if you already have valid registration tokens on your host pool and you want to retrieve them from an existing host pool.
If you are using Bicep templates in your deployment:
@sys.description('AVD Host Pool resource ID. (Default: )')
param hostPoolResourceId string
var varHostpoolSubId = split(hostPoolResourceId, '/')[2]
var varHostpoolRgName = split(hostPoolResourceId, '/')[4]
var varHostPoolName = split(hostPoolResourceId, '/')[8]
// GET hostpool
resource hostPoolGet 'Microsoft.DesktopVirtualization/hostPools@2023-09-05' existing = {
name: varHostPoolName
scope: resourceGroup('${varHostpoolSubId}', '${varHostpoolRgName}')
}
@sys.description('The registration token of the host pool. This is not secure! Only for educational/testing purposes. Please follow security practices @ https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/scenarios-secrets ')
output registrationToken array = hostPoolGet.listRegistrationTokens()
If you are using ARM templates in your deployment:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.28.1.47646",
"templateHash": "2750874554099795062"
}
},
"parameters": {
"hostPoolResourceId": {
"type": "string",
"metadata": {
"description": "AVD Host Pool resource ID. (Default: )"
}
}
},
"variables": {
"varHostpoolSubId": "[split(parameters('hostPoolResourceId'), '/')[2]]",
"varHostpoolRgName": "[split(parameters('hostPoolResourceId'), '/')[4]]",
"varHostPoolName": "[split(parameters('hostPoolResourceId'), '/')[8]]"
},
"resources": [],
"outputs": {
"registrationToken": {
"type": "array",
"metadata": {
"description": "The registration token of the host pool. This is not secure! Only for educational/ testing purposes. Please follow security practices @ https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/scenarios-secrets "
},
"value": "[listRegistrationTokens(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varHostpoolSubId')), format('{0}', variables('varHostpoolRgName'))), 'Microsoft.DesktopVirtualization/hostPools', variables('varHostPoolName')), '2023-09-05')]"
}
}
}
Other ways to take action
One alternative is to always (re)create your host pool, which in turn will re-generate registration tokens that can then be retrieved using the PUT operation.
If you are using Bicep templates in your deployment...
Use the retrieveToken.bicep module to retrieve the registration token from a host pool by using a PUT operation:
@sys.description('Optional. Host Pool token validity length. Usage: \'PT8H\' - valid for 8 hours; \'P5D\' - valid for 5 days; \'P1Y\' - valid for 1 year. When not provided, the token will be valid for 8 hours.')
param tokenValidityLength string = 'PT8H'
@sys.description('Generated. Do not provide a value! This date value is used to generate a registration token.')
param baseTime string = utcNow('u')
param vLocation string
param vHostPoolName string
param vHostPoolType string
param vPreferredAppGroupType string
param vMaxSessionLimit int
param vLoadBalancerType string
resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2023-09-05' = {
name: vHostPoolName
location: vLocation
properties: {
hostPoolType: vHostPoolType
preferredAppGroupType: vPreferredAppGroupType
maxSessionLimit: vMaxSessionLimit
loadBalancerType: vLoadBalancerType
registrationInfo: {
expirationTime: dateTimeAdd(baseTime, tokenValidityLength)
registrationTokenOperation: 'Update'
}
}
}
@sys.description('The registration token of the host pool.')
output registrationToken string = reference(hostPool.id).registrationInfo.token
Here's an example of using the retrieveToken.bicep module to extract the registration token:
@sys.description('AVD Host Pool resource ID. (Default: )')
param hostPoolResourceId string
var varHostpoolSubId = split(hostPoolResourceId, '/')[2]
var varHostpoolRgName = split(hostPoolResourceId, '/')[4]
var varHostPoolName = split(hostPoolResourceId, '/')[8]
// Call on the hostpool
resource hostPoolGet 'Microsoft.DesktopVirtualization/hostPools@2023-09-05' existing = {
name: varHostPoolName
scope: resourceGroup('${varHostpoolSubId}', '${varHostpoolRgName}')
}
module hostPool 'retrieveToken.bicep' = {
name: varHostPoolName
scope: resourceGroup('${varHostpoolSubId}', '${varHostpoolRgName}')
params: {
vHostPoolName: varHostPoolName
vMaxSessionLimit: hostPoolGet.properties.maxSessionLimit
vPreferredAppGroupType: hostPoolGet.properties.preferredAppGroupType
vHostPoolType: hostPoolGet.properties.hostPoolType
vLoadBalancerType: hostPoolGet.properties.loadBalancerType
vLocation: hostPoolGet.location
}
}
@sys.description('The registration token of the host pool.')
output registrationToken string = hostPool.outputs.registrationToken
If you are using ARM templates in your deployment:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.28.1.47646",
"templateHash": "15215789985349638425"
}
},
"parameters": {
"hostPoolName": {
"type": "string"
},
"location": {
"type": "string"
},
"baseTime": {
"type": "string",
"defaultValue": "[utcNow('u')]"
}
},
"variables": {
"expirationTime": "[dateTimeAdd(parameters('baseTime'), 'PT1H1M')]"
},
"resources": [
{
"type": "Microsoft.DesktopVirtualization/hostPools",
"apiVersion": "2023-09-05",
"name": "[parameters('hostPoolName')]",
"location": "[parameters('location')]",
"properties": {
"maxSessionLimit": 2,
"hostPoolType": "Personal",
"loadBalancerType": "Persistent",
"preferredAppGroupType": "Desktop",
"registrationInfo": {
"expirationTime": "[variables('expirationTime')]",
"registrationTokenOperation": "Update"
}
}
}
],
"outputs": {
"token": {
"type": "string",
"value": "[reference(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('hostPoolName'))).registrationInfo.token]"
}
}
}
WARNING! Be mindful when using secrets in deployment templates and follow Azure best practices when managing secrets. Our examples in this discussion post are to be used for educational purposes only. |
Additional Support
If you have any questions, comments, or concerns about this, please feel free to post a comment.
- JasonMastenMicrosoftWARNING! Secrets should never be used in the output section of an ARM template. The value will be stored in plain text in the portal and can be seen by anyone with the Reader role. The registration token should be passed to a key vault secret resource within the same deployment and referenced using the "getSecret" function in Bicep when it is needed: https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/key-vault-parameter?tabs=azure-cli#retrieve-secrets-in-bicep-file. Or use a key vault reference in JSON ARM templates: https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/key-vault-parameter?tabs=azure-cli#reference-secrets-with-dynamic-id
- yaegashiCopper Contributor
Logan_SillimanRegarding retrieveToken.bicep, it appears that the registration token is updated each time the module is invoked. Is it safe to execute multiple deployments with this module concurrently?
- Logan_SillimanMicrosoftGreat question! It depends! if this module is being invoked for different hostpools, then yes, it should be safe! If this module is invoked in parallel for the same hostpool, you will likely end up with conflicts.
The provided samples are are intended solely for educational purposes. You should adapt them to fit your production use cases: e.g. you can store the resulting hostpool registrationToken in a keyvault and have all subsequent deployments access this value from key vault.
Even better, you can start using listRegistrationTokens() function instead, which will retrieve existing tokens and won't recreate them.- JasonMastenMicrosoftLogan, where is the documentation for the new "listRegistrationTokens()" function?