Private/Resolve-TLAppId.ps1
|
function Resolve-TLAppId { <# .SYNOPSIS Resolves application (client) ids to service principal display names. .DESCRIPTION Conditional Access references applications by appId, not object id, so getByIds cannot be used. Uses $filter=appId in (...) in chunks of 15. Well-known tokens ('All', 'Office365', 'MicrosoftAdminPortals', 'None') pass through unchanged. #> [CmdletBinding()] param( [AllowEmptyCollection()] [AllowNull()] [string[]]$AppId ) $result = @{} if (-not $AppId -or @($AppId).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 @($AppId | Where-Object { $_ } | Sort-Object -Unique)) { if ($value -notmatch $guidPattern) { $result[$value] = $value; continue } if ($script:TLAppIdCache.ContainsKey($value)) { $result[$value] = $script:TLAppIdCache[$value]; continue } $toLookup.Add($value) } for ($offset = 0; $offset -lt $toLookup.Count; $offset += 15) { $chunk = @($toLookup[$offset..([Math]::Min($offset + 14, $toLookup.Count - 1))]) $filterExpression = "appId in ({0})" -f (($chunk | ForEach-Object { "'{0}'" -f $_ }) -join ',') $uri = '/v1.0/servicePrincipals?$filter=' + [uri]::EscapeDataString($filterExpression) + '&$select=appId,displayName' $found = @() try { $found = @(Invoke-TLGraphRequest -Uri $uri -All) } catch { Write-Verbose ("Service principal lookup failed for {0} appIds: {1}" -f $chunk.Count, $_.Exception.Message) } foreach ($servicePrincipal in $found) { $script:TLAppIdCache[$servicePrincipal.appId] = [string]$servicePrincipal.displayName $result[$servicePrincipal.appId] = [string]$servicePrincipal.displayName } foreach ($miss in $chunk) { if (-not $result.ContainsKey($miss)) { $script:TLAppIdCache[$miss] = $miss $result[$miss] = $miss } } } return $result } |