Private/Invoke-IntuneGraphRequest.ps1
|
function Invoke-IntuneGraphRequest { <# .SYNOPSIS Perform a specific call to Intune Graph API, either as GET, POST, PATCH, or DELETE. .DESCRIPTION Perform a specific call to Intune Graph API with retry logic for transient errors. .PARAMETER APIVersion The Graph API version (e.g., Beta, v1.0). .PARAMETER Route The API route (default: "deviceAppManagement"). .PARAMETER Resource The resource path for the API call. .PARAMETER Method The HTTP method to use (GET, POST, PATCH, DELETE). .PARAMETER Body The body of the request (for POST or PATCH). .PARAMETER ContentType The content type of the request (default: "application/json; charset=utf-8"). .NOTES Author: Nickolaj Andersen Contact: @NickolajA Created: 2020-01-04 Updated: 2024-12-24 Version history: 1.0.0 - (2020-01-04) Function created 1.0.1 - (2020-04-29) Added support for DELETE operations 1.0.2 - (2021-08-31) Updated to use new authentication header 1.0.3 - (2022-10-02) Changed content type for requests to support UTF8 1.0.4 - (2023-01-23) Added non-mandatory Route parameter to support different routes of Graph API in addition to better handle error response body depending on PSEdition 1.0.5 - (2023-02-03) Improved error handling 1.0.6 - (2025-01-14) Rewritten to handle transient errors and improved error handling for pipeline use. (tjgruber) #> param( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidateSet("Beta", "v1.0")] [string]$APIVersion, [parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$Route = "deviceAppManagement", [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Resource, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidateSet("GET", "POST", "PATCH", "DELETE")] [string]$Method, [parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [System.Object]$Body, [parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$ContentType = "application/json; charset=utf-8" ) # Retry parameters $RetryCount = 8 $RetryDelayRange = @{ Min = 7; Max = 30 } $TransientErrors = "TransientError|Timeout|ServiceUnavailable|TooManyRequests|429|503" for ($Attempt = 1; $Attempt -le $RetryCount; $Attempt++) { try { # Construct full URI $GraphURI = "https://graph.microsoft.com/$($APIVersion)/$($Route)/$($Resource)" Write-Verbose -Message "$($Method) $($GraphURI)" # Call Graph API and get JSON response switch ($Method) { "GET" { $GraphResponse = Invoke-RestMethod -Uri $GraphURI -Headers $Global:AuthenticationHeader -Method $Method -ErrorAction Stop -Verbose:$false } "POST" { $GraphResponse = Invoke-RestMethod -Uri $GraphURI -Headers $Global:AuthenticationHeader -Method $Method -Body $Body -ContentType $ContentType -ErrorAction Stop -Verbose:$false } "PATCH" { $GraphResponse = Invoke-RestMethod -Uri $GraphURI -Headers $Global:AuthenticationHeader -Method $Method -Body $Body -ContentType $ContentType -ErrorAction Stop -Verbose:$false } "DELETE" { $GraphResponse = Invoke-RestMethod -Uri $GraphURI -Headers $Global:AuthenticationHeader -Method $Method -ErrorAction Stop -Verbose:$false } } # If successful, return the response return $GraphResponse } catch [System.Net.WebException] { # Handle WebException for transient errors $StatusCode = $_.Exception.Response.StatusCode if ($StatusCode -eq 429 -or $StatusCode -eq 503) { $RetryDelay = Get-Random -Minimum $RetryDelayRange.Min -Maximum $RetryDelayRange.Max Write-Warning "Request failed with status code [$StatusCode]. Retrying in [$RetryDelay] seconds... (Attempt [$Attempt] of [$RetryCount])" Start-Sleep -Seconds $RetryDelay continue } # Handle non-retryable WebException Write-Warning "Non-retryable WebException occurred. Status code: [$StatusCode]. Message: [$($_.Exception.Message)]" throw $_ } catch { # Handle other exceptions (e.g., transient error patterns) if ($_.Exception.Message -match $TransientErrors) { $RetryDelay = Get-Random -Minimum $RetryDelayRange.Min -Maximum $RetryDelayRange.Max Write-Warning "Transient error detected. Retrying in [$RetryDelay] seconds... (Attempt [$Attempt] of [$RetryCount])" Start-Sleep -Seconds $RetryDelay continue } # Handle non-retryable errors Write-Warning "Non-retryable error occurred. Message: [$($_.Exception.Message)]" throw $_ } } # All retries failed throw "Graph request failed after [$RetryCount] attempts. Aborting." } |