Private/Get-AllGraphPage.ps1
|
function Get-AllGraphPage { <# .SYNOPSIS Retrieves all pages of results from a Microsoft Graph API endpoint. .DESCRIPTION Helper function to handle paginated results from Microsoft Graph API. Automatically follows @odata.nextLink to retrieve all pages and streams results to the pipeline as they are retrieved. By default, non-success responses result in warnings (silent failure). Use -ErrorAction Stop to throw terminating errors on non-success responses. .PARAMETER Uri The initial Microsoft Graph API URI to call. .PARAMETER ResourceName A friendly name for the resource being loaded, used in warning messages. .OUTPUTS [PSObject] Individual items from the 'value' array of each page, streamed to the pipeline as they are retrieved. Returns nothing on error (unless -ErrorAction Stop is specified). .EXAMPLE Get-AllGraphPage -Uri 'https://graph.microsoft.com/v1.0/users' -ResourceName 'Users' Retrieves all users from Microsoft Graph, handling pagination automatically. .EXAMPLE $usersUri = "$graphApiBase/users?`$select=id,displayName,userPrincipalName" $users = @(Get-AllGraphPage -Uri $usersUri -ResourceName "Users") .EXAMPLE # Throw on error instead of warning Get-AllGraphPage -Uri $uri -ResourceName 'Critical Data' -ErrorAction Stop #> [CmdletBinding()] [OutputType([PSObject])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Uri, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$ResourceName ) # Capture caller's ErrorAction preference before we override it $shouldThrow = $ErrorActionPreference -eq 'Stop' $ErrorActionPreference = 'Stop' $currentUri = $Uri # Verify Graph token is available for Graph API calls if ($Uri -match 'graph\.microsoft\.com' -and -not $script:GraphAccessToken) { $msg = "Graph API call requested but no Graph token available. Run Connect-CIEM first." if ($shouldThrow) { throw $msg } Write-Warning $msg return } while ($currentUri) { # Use Graph token for Graph API calls, Invoke-AzRestMethod for ARM if ($currentUri -match 'graph\.microsoft\.com') { $headers = @{ Authorization = "Bearer $script:GraphAccessToken" } $restResponse = Invoke-RestMethod -Uri $currentUri -Method GET -Headers $headers -ErrorAction SilentlyContinue -ErrorVariable restError -StatusCodeVariable statusCode $response = [PSCustomObject]@{ StatusCode = if ($statusCode) { $statusCode } elseif ($restError) { 400 } else { 200 } Content = if ($restResponse) { $restResponse | ConvertTo-Json -Depth 20 } else { $null } } } else { $response = Invoke-AzRestMethod -Uri $currentUri -Method GET } if (-not $response) { $msg = "Failed to load page for $ResourceName - No response" if ($shouldThrow) { throw $msg } Write-Warning $msg $currentUri = $null } elseif ($response.StatusCode -eq 200) { $content = $response.Content | ConvertFrom-Json if ($content.PSObject.Properties.Name -contains 'value') { $content.value } # Check for next page $currentUri = if ($content.PSObject.Properties.Name -contains '@odata.nextLink') { $content.'@odata.nextLink' } else { $null } } else { switch ($response.StatusCode) { 403 { $msg = "Access denied loading page for $ResourceName - missing permissions" if ($shouldThrow) { throw $msg } Write-Warning $msg } default { $msg = "Failed to load page for $ResourceName - Status: $($response.StatusCode)" if ($shouldThrow) { throw $msg } Write-Warning $msg } } $currentUri = $null } } } |