push
This commit is contained in:
@@ -149,40 +149,47 @@ function Get-PersonaGraphStatusCode {
|
||||
return $null
|
||||
}
|
||||
|
||||
function Test-PersonaTargetAttributeUnavailable {
|
||||
function Test-PersonaEnumerationRecoverable {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
True when a Graph 400 means the target attribute does not exist in this
|
||||
tenant, rather than some other client error.
|
||||
True when a Graph 400 during user enumeration is plausibly caused by the
|
||||
target attribute not existing in this tenant, and safe to retry without it.
|
||||
|
||||
.DESCRIPTION
|
||||
A dev tenant with no app registration has no persona extension property.
|
||||
Requesting it in $select then fails with 400 and a message naming the
|
||||
property. This distinguishes that specific, recoverable case from every
|
||||
other 400 (bad query syntax, an unrelated bad property, a permission denial
|
||||
phrased as 400), which must still fail loudly rather than being swallowed.
|
||||
A dev tenant with no app registration has no persona extension property, and
|
||||
requesting it in $select then fails with 400. The obvious approach - reading
|
||||
the offending property name out of the error - does not hold up in practice:
|
||||
Graph often returns a 400 with an empty body, and Invoke-MgGraphRequest then
|
||||
reports only "Response status code does not indicate success: BadRequest
|
||||
(Bad Request)." with no property name and not even a numeric status in the
|
||||
text (Get-PersonaGraphStatusCode still resolves it, from the structured
|
||||
Response.StatusCode rather than the message).
|
||||
|
||||
So this checks the only two facts actually available: the status was 400,
|
||||
and the target attribute was one of the properties requested. That is not
|
||||
proof the attribute is the cause, but confirming it is impossible from what
|
||||
Graph sends back, and the retry this justifies is cheap, read-only, and
|
||||
confined to preview mode - if the attribute was not the problem, the retry
|
||||
fails too and the original error still surfaces untouched.
|
||||
|
||||
.PARAMETER ErrorRecord
|
||||
The error caught from Invoke-PersonaGraphRequest.
|
||||
The error caught from Get-PersonaUsers.
|
||||
|
||||
.PARAMETER TargetAttribute
|
||||
The configured target attribute name.
|
||||
|
||||
.PARAMETER SelectProperties
|
||||
The $select list the failing request used.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
[OutputType([bool])]
|
||||
param(
|
||||
[Parameter(Mandatory)] $ErrorRecord,
|
||||
[Parameter(Mandatory)] [string] $TargetAttribute
|
||||
[Parameter(Mandatory)] [string] $TargetAttribute,
|
||||
[Parameter(Mandatory)] [AllowEmptyCollection()] [string[]] $SelectProperties
|
||||
)
|
||||
|
||||
if ((Get-PersonaGraphStatusCode -ErrorRecord $ErrorRecord) -ne 400) { return $false }
|
||||
|
||||
$text = @($ErrorRecord.Exception.Message, $ErrorRecord.ErrorDetails.Message) -join ' '
|
||||
if ([string]::IsNullOrWhiteSpace($text)) { return $false }
|
||||
|
||||
if ($text -notmatch [regex]::Escape($TargetAttribute)) { return $false }
|
||||
|
||||
[bool]($text -match '(?i)could not find a property|invalid property|is not a valid property|does not exist on type')
|
||||
((Get-PersonaGraphStatusCode -ErrorRecord $ErrorRecord) -eq 400) -and ($SelectProperties -ccontains $TargetAttribute)
|
||||
}
|
||||
|
||||
function Get-PersonaRetryAfterMs {
|
||||
|
||||
@@ -98,7 +98,7 @@ function Invoke-PersonaEngineRun {
|
||||
: @(Get-PersonaUsers -SelectProperties $selectProperties)
|
||||
}
|
||||
catch {
|
||||
if ((-not $IsEnforcing) -and (Test-PersonaTargetAttributeUnavailable -ErrorRecord $_ -TargetAttribute $TargetAttribute)) {
|
||||
if ((-not $IsEnforcing) -and (Test-PersonaEnumerationRecoverable -ErrorRecord $_ -TargetAttribute $TargetAttribute -SelectProperties $selectProperties)) {
|
||||
# Dev/test tenants often have no app registration yet, so the persona
|
||||
# extension property was never created. Preview mode never writes
|
||||
# regardless of what StoredPersona holds, so treating the attribute as
|
||||
@@ -106,7 +106,7 @@ function Invoke-PersonaEngineRun {
|
||||
# Enforcement still fails loudly - IsEnforcing gates this precisely
|
||||
# because writing to an attribute that does not exist must never be
|
||||
# silently tolerated.
|
||||
Write-Warning "Target attribute '$TargetAttribute' was not found in this tenant (no app registration / extension property?). Continuing in What-If mode with it treated as null for every account."
|
||||
Write-Warning "Graph rejected the request with a 400 while '$TargetAttribute' was in the requested properties. Retrying without it and treating it as null for this What-If run - if the retry also fails, the underlying error will be reported."
|
||||
|
||||
$fallbackProperties = @($selectProperties | Where-Object { $_ -cne $TargetAttribute })
|
||||
|
||||
|
||||
Reference in New Issue
Block a user