|
| 1 | +--- |
| 2 | +title: Handling errors in Microsoft Graph API requests with invoke-restmethod |
| 3 | +description: This article provides a code sample to simulate a handling error that occurs when you make requests to the Microsoft Graph API by using the Invoke-RestMethod cmdlet in PowerShell. |
| 4 | +ms.date: 02/18/2024 |
| 5 | +author: genlin |
| 6 | +ms.author: raheld |
| 7 | +ms.service: entra-id |
| 8 | +ms.topic: overview |
| 9 | +content_well_notification: AI-contribution |
| 10 | +ai-usage: ai-assisted |
| 11 | +ms.custom: sap:Microsoft Graph Users, Groups, and Entra APIs |
| 12 | +--- |
| 13 | +# Handling errors in Microsoft Graph API Requests with Invoke-RestMethod |
| 14 | + |
| 15 | +This article provides a code sample that demonstrates how to handle errors and implement retry logic when you make requests to the Microsoft Graph API by using the `Invoke-RestMethod` cmdlet in PowerShell. |
| 16 | + |
| 17 | +## Prerequisites |
| 18 | + |
| 19 | +- An Azure app registration with a client secret |
| 20 | +- The `user.read.all` permission for Microsoft.Graph for the Azure app. For more information, see [List users](/graph/api/user-get?view=graph-rest-1.0&tabs=http&preserve-view=true). |
| 21 | + |
| 22 | +## Code sample |
| 23 | + |
| 24 | +To demonstrate the retry logic, this sample tries to query the `signInActivity` data for guest users. When you run this code, you can expect to receive a "403" error. |
| 25 | + |
| 26 | +- **Get-AccessTokenCC** This function requests an access token from Microsoft Entra ID (formerly Azure Active Directory). The token will be used to authenticate API requests to Microsoft Graph. You have to provide values for the `$clientSecret`, `$clientId`, and `$tenantId` variables of your Azure registration app. |
| 27 | +- **Get-GraphQueryOutput ($Uri)** This function makes a request to the Microsoft Graph API to retrieve data. It also handles paging. The function retries the request if a "403" error is generated. |
| 28 | + |
| 29 | +``` powershell |
| 30 | +Function Get-AccessTokenCC |
| 31 | + |
| 32 | +{ |
| 33 | + $clientSecret = '' |
| 34 | + $clientId = '' |
| 35 | + $tenantId = '' |
| 36 | + # Construct URI |
| 37 | + $uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" |
| 38 | + # Construct Body |
| 39 | + $body = @{ |
| 40 | + client_id = $clientId |
| 41 | + client_secret = $clientSecret |
| 42 | + scope = 'https://graph.microsoft.com/.default' |
| 43 | + grant_type = 'client_credentials' |
| 44 | + } |
| 45 | + # Get OAuth 2.0 Token |
| 46 | + $tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType 'application/x-www-form-urlencoded' -Body $body -UseBasicParsing |
| 47 | + # Access Token |
| 48 | + $token = ($tokenRequest.Content | ConvertFrom-Json).access_token |
| 49 | + #$token = "Junk" #uncomment this line to cause a 401 error -- you can set that status in the error handler to test the pause and retry |
| 50 | + #Write-Host "access_token = $token" |
| 51 | + return $token |
| 52 | +} |
| 53 | + |
| 54 | +Function Get-GraphQueryOutput ($Uri) |
| 55 | +{ |
| 56 | + write-host "uri = $Uri" |
| 57 | + write-host "token = $token" |
| 58 | +
|
| 59 | + $retryCount = 0 |
| 60 | + $maxRetries = 3 |
| 61 | + $pauseDuration = 2 |
| 62 | + |
| 63 | + $allRecords = @() |
| 64 | + while ($Uri -ne $null){ |
| 65 | + Write-Host $Uri |
| 66 | + try { |
| 67 | + # todo: verify that the bearer token is still good -- hasn't expired yet -- if it has, then get a new token before making the request |
| 68 | + $result=Invoke-RestMethod -Method Get -Uri $Uri -ContentType 'application/json' -Headers @{Authorization = "Bearer $token"} |
| 69 | + |
| 70 | + Write-Host $result |
| 71 | + |
| 72 | + if($query.'@odata.nextLink'){ |
| 73 | + # set the url to get the next page of records. For more information about paging, see https://docs.microsoft.com/graph/paging |
| 74 | + $Uri = $query.'@odata.nextLink' |
| 75 | + } else { |
| 76 | + $Uri = $null |
| 77 | + } |
| 78 | + |
| 79 | + } catch { |
| 80 | + Write-Host "StatusCode: " $_.Exception.Response.StatusCode.value__ |
| 81 | + Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription |
| 82 | + |
| 83 | + if($_.ErrorDetails.Message){ |
| 84 | + Write-Host "Inner Error: $_.ErrorDetails.Message" |
| 85 | + } |
| 86 | + |
| 87 | + # check for a specific error so that we can retry the request otherwise, set the url to null so that we fall out of the loop |
| 88 | + if($_.Exception.Response.StatusCode.value__ -eq 403 ){ |
| 89 | + # just ignore, leave the url the same to retry but pause first |
| 90 | + if($retryCount -ge $maxRetries){ |
| 91 | + # not going to retry again |
| 92 | + $Uri = $null |
| 93 | + Write-Host 'Not going to retry...' |
| 94 | + } else { |
| 95 | + $retryCount += 1 |
| 96 | + Write-Host "Retry attempt $retryCount after a $pauseDuration second pause..." |
| 97 | + Start-Sleep -Seconds $pauseDuration |
| 98 | + } |
| 99 | + |
| 100 | + } else { |
| 101 | + # not going to retry -- set the url to null to fall back out of the while loop |
| 102 | + $Uri = $null |
| 103 | + } |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + $output = $allRecords | ConvertTo-Json |
| 108 | +
|
| 109 | +if ($result.PSObject.Properties.Name -contains "value") { |
| 110 | + return $result.value |
| 111 | +} else { |
| 112 | + return $result |
| 113 | +} |
| 114 | +} |
| 115 | + |
| 116 | +# Graph API URIs |
| 117 | +$uri = 'https://graph.microsoft.com/v1.0/users?$filter=userType eq ''Guest''&$select=displayName,UserprincipalName,userType,identities,signInActivity' |
| 118 | +
|
| 119 | +# Pull Data |
| 120 | +$token = Get-AccessTokenCC |
| 121 | +Get-GraphQueryOutput -Uri $uri|out-file c:\\temp\\output.json |
| 122 | +
|
| 123 | +``` |
| 124 | + |
| 125 | +## Capturing a specific header |
| 126 | + |
| 127 | +For advanced scenarios, such as capturing specific header values such as `Retry-After` during throttling responses (HTTP 429), use: |
| 128 | + |
| 129 | +```powershell |
| 130 | +$retryAfterValue = $_.Exception.Response.Headers["Retry-After"] |
| 131 | +``` |
| 132 | +To handle the "429 - too many requests" error, see [Microsoft Graph throttling guidance](/graph/throttling). |
| 133 | + |
| 134 | +[!INCLUDE [Azure Help Support](../../../includes/azure-help-support.md)] |
| 135 | + |
0 commit comments