Making batch calls to the Microsoft Graph API using the PowerShell SDK

How dealing with the API can feel

These past couple of weeks I’ve been doing a lot of work reporting on Azure Active Directory objects in preparation for an upcoming domain migration.

As ever, my tool of choice for these sort of activities is PowerShell: it’s a flexible language, with high level features, it can be stored as an Azure Automation runbook and you can get into the .NET weeds if you need.

Unfortunately the PowerShell SDK for Microsoft Graph is, like the Graph API itself still something of a work in progress. In this post, I’ll briefly demonstrate how to work around the current lack of support for batching.

Batching is an elegant enhancement to the Graph API whereby one can send upto 20 requests in one go, using a correlation ID to untangle the composite result that is returned. It’s performant and reduces the chattiness of an application using the graph API.

For instance, if one wants to extract all groups and members of the groups, first get all groups then, for each group, get the members. Using the Graph API we can reduce the number of API calls by a factor of 20. While the SDK doesn’t yet expose a batch command, we can use the all purpose invoke-mggraphrequest

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# get groups
$groups = get-mggroup -Top 1000

# Create batches, 20 at a time
for($i=0;$i -lt $groups.count;$i+=20){                                                                                                                                              
    $req = @{}                
	# Use select to create hashtables of id, method and url for each call                                     
    $req['requests'] = ($groups[$i..($i+19)] 
		| select @{n='id';e={$_.id}},@{n='method';e={'GET'}},`
		@{n='url';e={"/groups/$($_.id)/members"}})
    $response = invoke-mggraphrequest -Method POST `
		-URI "https://graph.microsoft.com/v1.0/`$batch" `
		-body ($req | convertto-json)
    $response.responses | foreach {                                    
        # process here ... check the status of each one, for example
        if($_.status -eq 200){
			# pull the members from $_.body
        } else {
            # exception handling
        }                                                      
    }                                                                                                                                              
}            

It’s a pretty elegant approach, helped by the fact that PowerShell arrays silently fail if for out of bounds indexes. For instance, if there are 95 groups, the last iteration of the loop will attempt to get items 80..99 but PowerShell will silently return items 80..94.