Table of Contents
Counting Fetched Objects is a Hard Computer Problem
All software has its own foibles, something clearly evident in the Microsoft Graph PowerShell SDK. You become accustomed to the little oddities and workaround known issues and all is well. But when the underlying foundation of software causes problems, it can cause a different level of confusion.
Take the question posed by MVP Aleksandar Nikolić on Twitter about how many accounts a Get-MgUser command will return (Figure 1).
The answer is 4 even though the command explicitly requests the return of the top 3 matching objects. Why does this happen? It’s all about Graph pagination and the way it’s implemented in Microsoft Graph PowerShell SDK cmdlets.
Pagination and Page Size
To understand what occurs, run the command with the debug switch to see the actual Graph requests posted by Get-MgUser. The first request is against the Users endpoint and requests the top 2 matching objects.
https://graph.microsoft.com/v1.0/users?$top=2
Note that the Graph request only includes a $top query parameter. This sets the page size of the query and matches the PageSize parameter in the Get-MgUser command. The Top parameter used with Get-MgUser has no significance for the Graph query because it’s purely used to tell PowerShell how many objects to show when the command completes. The use of Top in different contexts is confusing, but few people look behind the scenes to see how the cake is made.
The Graph request respects the page size and fetches 2 objects. However, we asked for 3 objects so some more work is needed to fetch the outstanding item. Microsoft’s Graph documentation says “When more than one query request is required to retrieve all the results, Microsoft Graph returns an @odata.nextLink property in the response that contains a URL to the next page of results.” The skiptoken or nextlink lets the command know that further data remains to be fetched, so it continues to fetch the next page with a request that includes the skiptoken:
https://graph.microsoft.com/v1.0/users?$top=2&$skiptoken=RFNwdAIAAQAAAFI6NWUyZWI1YWIub2ZmaWNlMzY1aXRwcm9zLmNvbV9lbWVhLnRlYW1zLm1zI0VYVCNAUmVkbW9uZEFzc29jaWF0ZXMub25taWNyb3NvZnQuY29tKVVzZXJfYmNmYTZlY2ItY2M1Yi00MzU3LTkwOWMtMWUwZTQ1MDg2NGUzuQAAAAAAAAAAAAA
The follow up request fetches the remaining page containing 2 more objects and completes processing. The person running the command sees 4 objects from the two pages. In effect, the Get-MgUser cmdlet ignores the instruction passes in the Top parameter to only show 3 objects.
The same processing happens with different combinations of page size and objects requested, and it’s the same for other cmdlets too. For instance, the command:
Get-MgGroup-Top 7 -PageSize 3
Returns 9 group objects because 3 page fetches are necessary. It seems odd, and it’s odder still that running Get-MgGroup -Top 7 without specifying a page size will return exactly what we asked for (7 objects), while using a larger page size returns all the objects that can be packed into the page:
Get-MgUser -Top 3 -PageSize 8 | Format-Table Id, DisplayName Id DisplayName -- ----------- 44c0ca9c-d18c-4466-9492-c60c3eb78423 12 Knocksinna (Gmail) bcfa6ecb-cc5b-4357-909c-1e0e450864e3 Email Channel for Exchange GOMs da1288d5-e63c-4118-af62-3280823e04e1 GOM Email List for Teams de67dc4a-4a51-4d86-9ee5-a3400d2c12ff Guest member - Project Condor 3e5a8c92-b9b6-4a45-a174-84ee97e5693f Arthur Smith 63699f2f-a46a-4e99-a068-47a773f9af11 Annie Jopes 7a611306-17d0-4ea0-922e-2924616d54d8 Andy David d8afc094-9c9b-4f32-86ee-fadd63b112b2 Aaron Jakes
Frustrating Paging and Display
The typical page size for a Graph request is 100 objects (but this can differ across resources), so it’s unusual to use the Top parameter to request a limited set of objects that’s larger than the default page size. Usually, I bump the page size up to 999 (the maximum) to reduce the number of requests made to fetch large quantities of user or group objects. Using a large page size can significantly affect the performance of queries retrieving large numbers of objects.
The conclusion is that changing the default page size for a Microsoft Graph PowerShell SDK cmdlet overrides the Top parameter. This kind of thing is commonly known as a bug and it’s very frustrating. The Graph requests work perfectly but then something gets in the way of restricting the output to the required number of objects.
Selecting Properties to Use
The same kind of problem arises when Microsoft changes the way Graph requests respond. For instance, this week I was asked why a script I included in an article about reporting Entra ID Managers and their Direct Reports didn’t work. The article dates from April 2023, so neither the text nor the script code is ancient.
Sometime in the intervening period, Microsoft made a change that affected the set of default properties returned by the Get-MgUser cmdlet (probably in the transition to V2.0 of the Microsoft Graph PowerShell SDK). The result meant that some of the properties returned when the script was written are not returned today. The fix is simple: use the Property parameter to specify the properties you expect to use in the script:
[array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All -PageSize 999 -Property Id, displayName, userprincipalName, department, city, country
I believe Microsoft made the change to reduce the strain on Graph resources. It’s annoying to be forced to update scripts because of external factors, especially when cmdlets appear to run smoothly and generate unexpected output.
More Handcrafting Required for the Microsoft Graph PowerShell SDK
The issues discussed here make me think that Microsoft should dedicate more engineering resources to perfecting the Microsoft Graph PowerShell SDK instead of creating a new Entra PowerShell module that duplicates Microsoft Graph PowerShell SDK cmdlets. The statement’s been made that the Entra cmdlets are better because they’re “handcrafted,” which I understand means that humans write the code for cmdlets. T
It’s nice that the Entra module gets such attention, but it would be nicer if the Graph PowerShell SDK received more human handcrafting and love to make it more predictable and understandable. Even Entra ID would benefit from that work.
Stay updated with developments across the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. We do the research to make sure that our readers understand the technology.
There is a lack of testing of all Microsoft Graph SDKs. They should be tested by people how have a deep knowledge of the Graph API.
Now, SDKs are tested by the end users and they don’t have time to report all issues. It’s happening since February 2023.
Even Aleksandar who is MVP doesn’t have the power to change anything. He can only complain on X. I agree that Entra module won’t bring any improvement, because it’s using SDK under the hood. A lot of people provided the feedback during MVP Summit, but I don’t see any results.
At this point, I’ve honestly given up on using the SDK for more than authenticating against the API and then running the Invoke-GraphRequest cmdlet. At some point I felt I had to know the nuts and bolts of the underlying API anyway to make sense of what the SDK does, so I might just go ahead and interact with the API in a more direct fashion.
That’s certainly an option… However, the SDK does has some plus points, such as paging management and automatic renewal of tokens.