Private/Invoke-TripwireGraphRequest.ps1
|
<# .SYNOPSIS The one read path to Microsoft Graph. GET only, with paging. .DESCRIPTION Every read in this module goes through here. The function has no -Method parameter and no -Body parameter, and the verb is hardcoded at the single call site, so a future commit cannot quietly turn a read into a write by passing an argument. Writes have their own gateway with an explicit allowlist (Invoke-TripwireGraphWrite); there are exactly two ways to reach Graph from this module and both are audited by tests. Paging follows @odata.nextLink. On HTTP 429 it honours Retry-After, because a detector that gives up halfway through the sign-in log reports fewer touches than happened -- the failure mode that looks like good news. #> function Invoke-TripwireGraphRequest { [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Uri, [int] $MaxPages = 50, [int] $MaxRetry = 4 ) $results = [System.Collections.Generic.List[object]]::new() $next = $Uri $page = 0 while ($next -and $page -lt $MaxPages) { $page++ $attempt = 0 $response = $null while ($true) { $attempt++ try { # GET is hardcoded. This is the only place the module issues a read. $response = Invoke-MgGraphRequest -Method GET -Uri $next -OutputType PSObject -ErrorAction Stop break } catch { $status = $null if ($null -ne $_.Exception.Response) { $status = [int]$_.Exception.Response.StatusCode } if (($status -eq 429 -or $status -ge 500) -and $attempt -le $MaxRetry) { $delay = [Math]::Min([Math]::Pow(2, $attempt), 30) Write-TripwireLog -Level 'Warn' -Message "Graph returned $status for $next; retry $attempt in ${delay}s." Start-Sleep -Seconds $delay continue } throw "Graph GET failed for '$next': $($_.Exception.Message)" } } if ($null -ne $response.value) { $results.AddRange(@($response.value)) } elseif ($null -ne $response) { $results.Add($response) } $next = $response.'@odata.nextLink' } if ($next) { # Truncation is reported, never swallowed. A partial log read that looks complete # is how a detector says "nothing happened" about pages it never fetched. Write-TripwireLog -Level 'Warn' -Message "Stopped after $MaxPages pages; results are TRUNCATED. Narrow the time window or raise -MaxPages." } # Enumerated, not comma-wrapped: callers write @(Invoke-TripwireGraphRequest ...), and # ,$array there would produce a one-element array holding the whole page set. return $results.ToArray() } |