Private/Get-PSDVFunctionRuntimeManagedIdentityAccessToken.ps1

function Get-PSDVFunctionRuntimeManagedIdentityAccessToken {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [Hashtable]
        $AuthContext
    )

    $resource = $AuthContext.ResourceUrl.TrimEnd('/')
    $managedIdentityID = $AuthContext.ManagedIdentityID

    if (-not [string]::IsNullOrWhiteSpace($env:IDENTITY_ENDPOINT) -and -not [string]::IsNullOrWhiteSpace($env:IDENTITY_HEADER)) {
        $query = [ordered]@{
            'api-version' = '2019-08-01'
            resource      = $resource
        }

        if (-not [string]::IsNullOrWhiteSpace($managedIdentityID)) {
            if ($managedIdentityID.StartsWith('/subscriptions/', [System.StringComparison]::OrdinalIgnoreCase)) {
                $query['mi_res_id'] = $managedIdentityID
            }
            else {
                $query['client_id'] = $managedIdentityID
            }
        }

        $uriBuilder = [System.UriBuilder]::new($env:IDENTITY_ENDPOINT)
        $uriBuilder.Query = ($query.GetEnumerator() | ForEach-Object { '{0}={1}' -f [System.Net.WebUtility]::UrlEncode($_.Key), [System.Net.WebUtility]::UrlEncode($_.Value) }) -join '&'
        $headers = @{
            'X-IDENTITY-HEADER' = $env:IDENTITY_HEADER
        }

        $response = Invoke-RestMethod -Method Get -Uri $uriBuilder.Uri.AbsoluteUri -Headers $headers -ErrorAction Stop
    }
    elseif (-not [string]::IsNullOrWhiteSpace($env:MSI_ENDPOINT) -and -not [string]::IsNullOrWhiteSpace($env:MSI_SECRET)) {
        $query = [ordered]@{
            'api-version' = '2017-09-01'
            resource      = $resource
        }

        if (-not [string]::IsNullOrWhiteSpace($managedIdentityID)) {
            $query['clientid'] = $managedIdentityID
        }

        $uriBuilder = [System.UriBuilder]::new($env:MSI_ENDPOINT)
        $uriBuilder.Query = ($query.GetEnumerator() | ForEach-Object { '{0}={1}' -f [System.Net.WebUtility]::UrlEncode($_.Key), [System.Net.WebUtility]::UrlEncode($_.Value) }) -join '&'
        $headers = @{
            Secret = $env:MSI_SECRET
        }

        $response = Invoke-RestMethod -Method Get -Uri $uriBuilder.Uri.AbsoluteUri -Headers $headers -ErrorAction Stop
    }
    else {
        throw 'Function runtime managed identity token acquisition requires IDENTITY_ENDPOINT and IDENTITY_HEADER environment variables, or legacy MSI_ENDPOINT and MSI_SECRET environment variables.'
    }

    if ([string]::IsNullOrWhiteSpace($response.access_token)) {
        throw 'Function runtime managed identity endpoint did not return an access token.'
    }

    $expiresOn = $null
    if ($response.expires_on) {
        $expiresOnText = [string]$response.expires_on
        $epochSeconds = 0L
        if ([Int64]::TryParse($expiresOnText, [ref]$epochSeconds)) {
            $expiresOn = [DateTimeOffset]::FromUnixTimeSeconds($epochSeconds).UtcDateTime
        }
        else {
            $expiresOn = ([DateTimeOffset]::Parse($expiresOnText, [Globalization.CultureInfo]::InvariantCulture)).UtcDateTime
        }
    }
    elseif ($response.expires_in) {
        $expiresOn = (Get-Date).ToUniversalTime().AddSeconds([Int32]$response.expires_in)
    }
    else {
        throw 'Function runtime managed identity endpoint did not return token expiration metadata.'
    }

    return [PSCustomObject]@{
        Token     = ConvertTo-SecureString -String $response.access_token -AsPlainText -Force
        ExpiresOn = $expiresOn
    }
}