PRT.ps1

# This file contains functions for Persistent Refresh Token and related device operations

# Creates a new BPRT
# Oct 20th 2020
function New-BulkPRTToken
{
<#
    .SYNOPSIS
    Creates a new BPRT (Bulk AAD PRT Token)
 
    .DESCRIPTION
    Creates a new BPRT (Bulk AAD PRT Token) for registering multiple devices to AAD.
    Adds a corresponding user to Azure AD with UPN "package_<guid>@<default domain>". The Display Name of the user can be defined.
 
    .Parameter AccessToken
    Access token to create the BPRT
 
    .Parameter Expires
    The date when the BPRT expires. Maximum is 180 days.
 
    .Parameter Name
    The display name of the user to be created. Defaults to "package_<guid>". The upn will always be "package_<guid>@<default domain>".
 
    .Parameter PackageId
    Package Id of the previously created BPRT. Overwrites the existing user object and creates a new BPRT. If not found, a new one is created.
 
    .EXAMPLE
    Get-AADIntAccessTokenForAADGraph -Resource urn:ms-drs:enterpriseregistration.windows.net -SaveToCache
    PS C:\> New-AADIntBulkPRTToken -Name "My BPRT user"
 
    BPRT saved to package_8eb8b873-2b6a-4d55-bd96-27b0abadec6a-BPRT.json
#>

    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$False)]
        [String]$AccessToken,
        [Parameter(Mandatory=$False)]
        [DateTime]$Expires=(Get-Date).AddMonths(1),
        [Parameter(Mandatory=$False)]
        [ValidateLength(1, 256)]
        [String]$Name,
        [Parameter(Mandatory=$False)]
        [guid]$PackageId=(New-Guid),
        [switch]$Force
    )
    Process
    {
        # Get from cache if not provided
        $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientId "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "urn:ms-drs:enterpriseregistration.windows.net" -Force $Force

        $headers = @{
            "Authorization" = "Bearer $AccessToken"
        }

        if([string]::IsNullOrEmpty($Name))
        {
            $Name = "package_$($PackageId.ToString())"
        }

        $body = @{
            "pid" =  $PackageId.ToString()
            "name" = $Name
            "exp" =  $Expires.ToString("MM/dd/yyyy")
        }

        # Make the first request to get flowToken
        $response = Invoke-RestMethod -UseBasicParsing -Method Post -Uri "https://login.microsoftonline.com/webapp/bulkaadjtoken/begin" -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json; charset=utf-8"

        if($response.state -like "*Error*")
        {
            $resultData = $response.resultData | ConvertFrom-Json
            throw $resultData.error_description
        }

        # Get the BPRT
        $response = Invoke-RestMethod -UseBasicParsing -Method Get -Uri "https://login.microsoftonline.com/webapp/bulkaadjtoken/poll?flowToken=$($response.flowToken)" -Headers $headers

        $details = $response.resultData | ConvertFrom-Json

        # Check for the errors
        if($details.error_description)
        {
            if($details.error -eq "unauthorized_client")
            {
                Write-Warning "Got unauthorized_client error. Please try again."
            }
            elseif($details.error_description.StartsWith("AADSTS90092"))
            {
                # Missing Microsoft.Azure.SyncFabric service principal?
                try
                {
                    if([string]::IsNullOrEmpty((Get-ServicePrincipals -ClientIds "00000014-0000-0000-c000-000000000000").value))
                    {
                        Write-Warning "Missing Microsoft.Azure.SyncFabric service principal!"
                        Write-Warning "Use Add-AADIntSyncFabricServicePrincipal to add the missing service principal."
                    }

                }
                catch{} # Okay
            }
            throw $details.error_description
        }

        $parsedIdToken = Read-Accesstoken -AccessToken $details.id_token

        $userName = $parsedIdToken.upn

        Write-Verbose "BPRT successfully created. Id = $guid. User name: $userName"

        # Write to file
        $outFileName = "$($userName.Split("@")[0])-BPRT.json"
        $details | ConvertTo-Json |Set-Content $outFileName -Encoding UTF8
        Write-Host "BPRT saved to $outFileName`n"

        return $details.refresh_token
    }
}