Microsoft GraphPowershell

I want more! The Graph result limit of 100 (or 999)

PowerShell scripting with the Microsoft Graph API is a nice thing because you can access some pieces of information that you cannot gather elsewhere with scripting. If you never did it, please visit the detailed blog post which describes Graph Scripting for Beginners :).

What has always annoyed me is Graph’s habit of only returning a maximum of 100 objects for standard queries. This applies, for example, when you query the list of USer accounts, but also for querying the members of a group. Or events in the audit log. So if you’re just doing this, don’t be surprised that your result list is only complete in tiny environments:

$url = 'https://graph.microsoft.com/v1.0/users'
$userList = (Invoke-WebRequest -UseBasicParsing -Headers $headerParams -Uri $url) | Convert-FromJson

ForEach ($user In $userList.Value) {
    $user
}

First aid: Adding a larger page size to the request. The sub-API for user objects in Microsoft Graph allows us to set a page size of 999 max:

$url = 'https://graph.microsoft.com/v1.0/users?$top=999'
$userList = Invoke-WebRequest -UseBasicParsing -Headers $headerParams -Uri $url | ConvertFrom-Json

ForEach ($user In $userList.Value) {
    $user
}

Please note also that some other sub-APIs of Graph may differ in terms of the maximum page size. Or in their behavior, if you specify a page size that is too large. Either the page size is automatically reset to the permitted maximum, or the request comes back with an error, or (worst case) no error is thrown and no result is returned. So choose the $top value carefully.

Getting it all – Paged Result Queries

The ultimate solution for this problem is this easy. Use the $top parameter but look for the @odata.nextLink property in the result – if it not empty, then there are more result entries to read. Fortunately, the content of this @odata.nextLink is just the URL that you use in the looped next query. Do this until @odata.nextLink is empty. Then you have the complete list!

Microsoft describes this paging technique is here: https://docs.microsoft.com/en-us/graph/paging.

The following script is a basic example for paged results: Getting the complete user list. It’s starting with business as usual, but then we loop the GET request as long as there is no more data left. In the loop, we fill our result array. You can use this method with every other Graph request that you want to perform with paging:

$clientID     = "e5c9378d-7739-4d23-bf96-41c451900d71"    #  <-insert your own app ID here
$clientSecret = "M3X9hGJb432y.tTxOsQ.ZNK~8hP4tc6.uY"      #  <-insert your own secret here
$tenantDomain = "M365x824127.onmicrosoft.com"             #  <-insert your own tenant id here
 
$loginURL     = "https://login.microsoft.com"
$resource     = "https://graph.microsoft.com"
$body         = @{grant_type="client_credentials";resource=$resource;client_id=$ClientID;client_secret=$ClientSecret}
$oauth        = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-version=1.0 -Body $body
$headerParams = @{'Authorization'="$($oauth.token_type) $($oauth.access_token)"}

#_____________________________________________________________________________________________

$userList = @()
$url = 'https://graph.microsoft.com/v1.0/users?&$top=999'

While ($url -ne $Null) {
    $data = (Invoke-WebRequest -Headers $headerParams -Uri $url) | ConvertFrom-Json
    $userList += $data.Value
    $url = $data.'@Odata.NextLink'
}

$userList

By the way: If you get an error message like this: “Application with identifier ‘xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx’ was not found in the directory….”, then you need to register an application first for your Graph scripting. Please follow the preparation steps outlined in the basic blog post about How to use the Graph API with Powershell.

Leave a Reply

Your email address will not be published. Required fields are marked *