Verifying Azure AD tenant availability

My colleague Yannick Dils (who specializes in digital transformation, cloud adoption, and modern workplace projects) and I were at the virtual water cooler when we found ourselves in a discussion about automating certain aspects of a migration project. Yannick stumbled upon a conundrum: “How do we check whether or not an Azure AD tenant is in use, without access to Microsoft Partner Center”?

This made me think of a particular anecdote about a small web application that I wrote years ago to help onboard new customers into Microsoft Partner Center, way back when there was no managed SDK to speak of. I decided to write my library around the Partner Center REST API, if memory serves me right there was no way to check for the availability of an Azure AD tenant. Nowadays you can get the tenant’s name availability without issue, via the managed SDK. Let’s look at how we can check the availability with and without access to Microsoft Partner Center.

Microsoft Partner Center

Should you have access to Partner Center, you can certainly use one of the following methods to check the availability of an Azure AD tenant name.

Through the .NET SDK you could do something like this in C# (or any .NET powered language):

IAggregatePartner partnerOperations;
// Continue the partnerOperations setup ceremony
const string domain = "contoso.onmicrosoft.com";
bool result = partnerOperations.Domains.ByDomain(domain).Exists();

It’s even easier with the Partner Center PowerShell module:

Connect-PartnerCenter
Test-PartnerDomainAvailability -Domain 'contoso.onmicrosoft.com'

And even if all else fails, we can fall back to the Partner Center REST API:

HEAD https://api.partnercenter.microsoft.com/v1/domains/contoso.onmicrosoft.com HTTP/1.1
Authorization: Bearer <token>
Accept: application/json

DIY-edition

Back in 2015, I used a very inconspicuous trick to check the tenant availability, and too much of my surprise, it still works, to this day.

I used to check for the presence of a particular XML file, one that should be present in all Azure Active Directory tenants, even your own! The Microsoft identity platform uses the SAML 2.0 protocol to enable applications to supply a single sign-on experience to their users and we can use that to our advantage.

Here is what the dev docs say about the subject:

Azure Active Directory exposes tenant-specific and common (tenant-independent) single sign-on and single sign-out endpoints. These URLs represent addressable locations – they are not just identifiers – so you can go to the endpoint to read the metadata.

There are two endpoints and we’re only looking for the information surrounding the “tenant-specific” endpoint:

  • The tenant-specific endpoint is located at “https://login.microsoftonline.com/<TenantDomainName>/FederationMetadata/2007-06/FederationMetadata.xml”.
    • The “<TenantDomainName>” placeholder represents a registered domain name or TenantID GUID of an Azure AD tenant.
    • For example, the federation metadata of the “contoso.com” tenant is at “https://login.microsoftonline.com/contoso.com/FederationMetadata/2007-06/FederationMetadata.xml
  • The tenant-independent endpoint is located at “https://login.microsoftonline.com/common/FederationMetadata/2007-06/FederationMetadata.xml”.
    • In this endpoint address, common appears instead of a tenant domain name or ID.

Based on that information I assumed that:

  • When I browse to an existing Azure AD tenant, I will get the XML data and an HTTP status code 200.
  • When I browse to an Azure AD tenant that should not exist, I will get a different HTTP status code. For simplicity’s sake, I will assume that it will exclusively send me a 404-status code but be careful with these kinds of assumptions as this behavior could change in the future.

Armed with that knowledge we can go ahead to wrap this up into anything we want, a PowerShell script will be enough for our automation purposes. Here’s a little sample we cooked up, which you can also view on GitHub:

#Requires -Version 7.0

<#
.SYNOPSIS
    Checks whether an Azure AD tenant is available.
.DESCRIPTION
    Checks whether an Azure AD tenant is available.
.PARAMETER FQDN
    Provide the fully qualified domain name.
.INPUTS
    None. You cannot pipe objects to Get-AzureAdTenantAvailability.
.OUTPUTS
    System.Boolean. Get-AzureAdTenantAvailability returns a Boolean:
        - $true indicates the tenant's name is available.
        - $false indicates the tenant's name is unavailable.
.EXAMPLE
    PS C:\> .\Get-AzureAdTenantAvailability.ps1 -FQDN "thomasvanlaere.com"
.EXAMPLE
    PS C:\> .\Get-AzureAdTenantAvailability.ps1 -FQDN "www.tunecom.be"
.EXAMPLE
    PS C:\> .\Get-AzureAdTenantAvailability.ps1 -FQDN "even-this.works.co.uk"
.EXAMPLE
    PS C:\> .\Get-AzureAdTenantAvailability.ps1 -FQDN "contoso.onmicrosoft.com"
#>
[CmdletBinding()]
param (
    [Parameter(
        Mandatory = $true,
        HelpMessage = "Provide the fully qualified domain name.")]
    [string]
    $FQDN
)

if ($FQDN -notmatch "(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\.)+[a-zA-Z]{2,63}$)") {
    Write-Error -Message ("FQDN used incorrect format: '{0}'." -f $FQDN) -ErrorAction Stop
}

$uri = "https://login.microsoftonline.com/{0}/FederationMetadata/2007-06/FederationMetadata.xml" -f $FQDN
Write-Verbose ("Sending request to '{0}'." -f $uri)
$response = Invoke-WebRequest -Uri $uri -Method GET -SkipHttpErrorCheck
switch ($response.StatusCode) {
    200 {
        Write-Verbose "Received 200 status code, the tenant's name is unavailable."
        return $false
    }
    404 {
        Write-Verbose "Received 404 status code, the tenant's name is available."
        return $true
    }
    default {
        Write-Error -Message "Unable to determine result." -ErrorAction Stop
        break;
    }
}

As you might have been able to tell PowerShell 7.0+ is required; “Invoke-WebRequest” does not have the “-SkipHttpErrorCheck” parameter in PowerShell 5.1 and thus this script will not function as is. You could rewrite the script for PowerShell 5.1 so it takes advantage of a “try/catch” block, in order to capture the status code, more info on how to do that here. You could also rewrite the script so you check the “$PsVersionTable” and then branch the logic off from there, the choice is entirely yours.

Conclusion

Granted there is probably a very limited use case for verifying an Azure AD tenant name, but it was something we bumped into at least twice in the last five years (🙃). Regardless of which possibility suits you best, I hope this has been insightful!