AppleBusinessManager.psm1

#Requires -Version 7.0
#Requires -Module jwtPS
function Connect-AppleBusinessManager {
    if (-not $Env:AppleBusinessManagerClientId -or -not $Env:AppleBusinessManagerPrivateKeyId -or -not $Env:AppleBusinessManagerPrivateKey) {
        throw "Client ID, Private Key ID and Private Key environment variables were not set for Apple Business Manager"
    }
    $Script:ClientId = $Env:AppleBusinessManagerClientId
    $Script:PrivateKey = $Env:AppleBusinessManagerPrivateKey
    $Script:PrivateKeyId = $Env:AppleBusinessManagerPrivateKeyId

    $Header = @{
        'kid' = $Script:PrivateKeyId
    }

    $Payload = @{
        aud = "https://account.apple.com/auth/oauth2/v2/token" 
        iss = $Script:ClientId
        sub = $Script:ClientId
        iat = ([System.DateTimeOffset]::Now).ToUnixTimeSeconds()
        exp = ([System.DateTimeOffset]::Now.AddMinutes(15)).ToUnixTimeSeconds()
        jti = [guid]::NewGuid()
    }

    $Hashing = [jwtTypes+encryption]::SHA256
    $Signature = [jwtTypes+algorithm]::ECDsa
    $Algorithm = [jwtTypes+cryptographyType]::new($Signature, $Hashing)
    $JWT = New-JWT -Payload $Payload -Algorithm $Algorithm -Secret $Script:PrivateKey -Header $Header
    Write-Verbose $JWT

    $Script:Body = @{
        'grant_type'            = 'client_credentials'
        'client_id'             = $Script:ClientId
        'client_assertion'      = $JWT
        'client_assertion_type' = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
        'scope'                 = 'business.api'
    }

    $Script:AuthResponse = Invoke-RestMethod -Method Post -Uri 'https://account.apple.com/auth/oauth2/token' -Body $Script:Body -SkipHttpErrorCheck
    if ($Script:AuthResponse.error) {
        throw $Script:AuthResponse.Error
    }
    $Script:ExpiresAt = (Get-Date).AddSeconds($Script:AuthResponse.expires_in)
}

function Get-AppleBusinessManagerBearerToken {
    if (-not $Script:AuthResponse) {
        try {
            Connect-AppleBusinessManager
        }
        catch {
            throw "Authorization has not been completed, use Connect-AppleBusinessManager first."
        }
    }
    if ((Get-Date).AddMinutes(1) -ge $Script:ExpiresAt) {
        # Access token is approaching expiration, get a new access token
        Connect-AppleBusinessManager
    }

    return ($Script:AuthResponse.access_token | ConvertTo-SecureString -AsPlainText -Force)
}

function Invoke-AppleBusinessManagerPagedApiRequest {
    param (
        [Parameter(Mandatory = $true)][uri] $Uri
    )
    $Results = New-Object System.Collections.ArrayList
    while ($Uri) {
        $Result = Invoke-RestMethod $Uri -Authentication Bearer -Token (Get-AppleBusinessManagerBearerToken) -ErrorAction Stop
        $Uri = $Result.links.next
        $Results.AddRange($Result.data) | Out-Null
    }
    return $Results
}

function Get-AppleBusinessManagerOrgDevices {
    return Invoke-AppleBusinessManagerPagedApiRequest -Uri "https://api-business.apple.com/v1/orgDevices"
}

function Get-AppleBusinessManagerMdmServers {
    return Invoke-AppleBusinessManagerPagedApiRequest -Uri "https://api-business.apple.com/v1/mdmServers"
}