Private/Get-MsecGraphErrorMessage.ps1
|
function Get-MsecGraphErrorMessage { <# .SYNOPSIS Pulls Microsoft Graph's own error message out of a terminating error record. .DESCRIPTION Graph puts the useful text in the RESPONSE BODY, which PowerShell surfaces on $_.ErrorDetails.Message. It is NOT in $_.Exception.Message, which carries only the bare status line - "Response status code does not indicate success: 403 (Forbidden)." That distinction matters whenever one status code has several causes. /auditLogs/signIns and /reports/authenticationMethods/userRegistrationDetails both return 403 either because the app lacks a permission OR because the tenant has no Entra ID premium licence, and those need opposite responses: grant-and-consent versus buy-a-licence or accept-not-applicable. Blaming the permission unconditionally sends people through a consent cycle that cannot help, so callers must read what Graph actually said. Falls back through: Graph's `error.message` -> the raw response body (when it isn't JSON) -> the exception message. Never throws, so it is safe to call from a catch block. .PARAMETER ErrorRecord The ErrorRecord caught from a failed Invoke-MsecGraphRequest / Invoke-RestMethod call. .EXAMPLE catch { $detail = Get-MsecGraphErrorMessage $_ if ($detail -match 'premium|B2C') { throw "…licensing…" } throw "…permission…" } #> [CmdletBinding()] param( [Parameter(Mandatory, Position = 0)] $ErrorRecord ) $detail = $null if ($ErrorRecord.ErrorDetails -and $ErrorRecord.ErrorDetails.Message) { # A JSON body is the normal case; a proxy or gateway can return plain text instead. $detail = try { ($ErrorRecord.ErrorDetails.Message | ConvertFrom-Json).error.message } catch { $ErrorRecord.ErrorDetails.Message } } if (-not $detail -and $ErrorRecord.Exception) { $detail = $ErrorRecord.Exception.Message } return [string]$detail } |