Private/Resolve-TLObjectId.ps1

function Resolve-TLObjectId {
    <#
    .SYNOPSIS
        Resolves directory object GUIDs to display names via a session-wide cache.
    .DESCRIPTION
        Uses POST /directoryObjects/getByIds in chunks of 1000. Non-GUID values
        ('All', 'None', 'GuestsOrExternalUsers', ...) pass through unchanged.
        Returns a hashtable: id -> @{ DisplayName; Type }.
    #>

    [CmdletBinding()]
    param(
        [AllowEmptyCollection()]
        [AllowNull()]
        [string[]]$Id
    )

    $result = @{}
    if (-not $Id -or @($Id).Count -eq 0) { return $result }

    $guidPattern = '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$'
    $toLookup = [System.Collections.Generic.List[string]]::new()

    foreach ($value in @($Id | Where-Object { $_ } | Sort-Object -Unique)) {
        if ($value -notmatch $guidPattern) {
            $result[$value] = @{ DisplayName = $value; Type = 'wellKnown' }
            continue
        }
        if ($script:TLResolverCache.ContainsKey($value)) {
            $result[$value] = $script:TLResolverCache[$value]
            continue
        }
        $toLookup.Add($value)
    }

    for ($offset = 0; $offset -lt $toLookup.Count; $offset += 1000) {
        $chunk = @($toLookup[$offset..([Math]::Min($offset + 999, $toLookup.Count - 1))])
        $found = @()
        try {
            $found = @(Invoke-TLGraphRequest -Method POST -Uri '/v1.0/directoryObjects/getByIds' -Body @{ ids = @($chunk) } -All)
        }
        catch {
            Write-Verbose ("getByIds lookup failed for {0} ids: {1}" -f $chunk.Count, $_.Exception.Message)
        }
        foreach ($object in $found) {
            $entry = @{
                DisplayName = [string]$object.displayName
                Type        = ([string]$object.'@odata.type') -replace '^#microsoft\.graph\.', ''
            }
            $script:TLResolverCache[$object.id] = $entry
            $result[$object.id] = $entry
        }
        foreach ($miss in $chunk) {
            if (-not $result.ContainsKey($miss)) {
                # Deleted objects are not returned by getByIds - keep the id visible.
                $entry = @{ DisplayName = "unresolved ($miss)"; Type = 'unknown' }
                $script:TLResolverCache[$miss] = $entry
                $result[$miss] = $entry
            }
        }
    }

    return $result
}