The old ways

Up until now I’ve been using the reference function fetch a registration token. It’s possible to specify an explicit api-version:

output token1 object = reference(hostPool.id, '2023-09-05').registrationInfo.token
output token2 string = reference(hostPool.id).registrationInfo.token

The bicep compiles to this json:

"[reference(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('hostpoolName')), '2023-09-05').registrationInfo.token]"
"[reference(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('hostpoolName'))).registrationInfo.token)]"

Recent errors

Recently these deployments has began to fail in some envornments, with the errors:

  1. …The language expression property ’token’ can’t be evaluated.

  2. …Expected a value of type ‘String, Uri’ but received a value of type ‘Null’.

azure deployment property error
DSC extension AddSessionHost - expression property 'token' can't be evaluated
azure deployment property error
expression property 'token' can't be evaluated
azure deployment type error
received a value of type 'null'

Introducing listRegistrationTokens()

In GitHub issue Azure/bicep-types-az/issues/2023 Microsoft FTE @shenglol shows the new resource function listRegistrationTokens(). The function is as of 2024.08.12 not yet documented in the bicep documentation or outside of the API spec, to the best of my knowledge… The API-call is documented here

The function returns object with a list of objects with a token and the expirationTime:

{
  "value": [
    {
      "expirationTime": "2024-08-13T00:00:00Z",
      "token": "eyJh[REDACTED].eyJS[REDACTED].Kii[REDACTED]"
    }
  ]
}

Here is some usage with it:

output tokenRootObject object = hostpool.listRegistrationTokens()
output tokenList array = hostpool.listRegistrationTokens().value
output tokenInnerObj object = hostpool.listRegistrationTokens().value[0]
output token string = first(hostpool.listRegistrationTokens().value).token

Linter support

Usage of any list* function allows the linter to know this is a secret, and give recommendations based on that. In the old ways, the api-versions had the token property not marked as a secret, thus allowing it to be fetched though GET requests.

vscode linter shows warning
linter - possible secret

Full Bicep example

Full bicep example (CLICK TO EXPAND)
@description('The name of the hostpool')
param hostpoolName string = 'vdpool-listregtoken-001'

@description('Location for all resources to be created in.')
param location string = resourceGroup().location

param tokenExpirationTime string = dateTimeAdd(utcNow('yyyy-MM-dd T00:00:00'), 'P1D', 'o')

resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2023-09-05' = {
  name: hostpoolName
  location: location
  properties: {
    hostPoolType: 'Pooled'
    loadBalancerType: 'BreadthFirst'
    maxSessionLimit: 5
    description: 'first avd host pool'
    friendlyName: 'friendly name'
    preferredAppGroupType: 'Desktop'
    registrationInfo: {
      expirationTime: tokenExpirationTime
      registrationTokenOperation: 'Update'
    }
  }
}

// old
// output registrationInfo object = reference(hostPool.id).registrationInfo
// output token object = reference(hostPool.id).registrationInfo.token

// new
output registrationTokens object = first(hostPool.listRegistrationTokens().value)
output token object = first(hostPool.listRegistrationTokens().value).token