2 February, 2024

How to extract Graph API data from Microsoft portals

As a consultant, I'm often given access to customer environments, and need to extract data through the various Microsoft portals.

But, reviewing existing environments through a portal is slow. What I really want is the raw data, so that I can use my various scripts and tools to summarise the results, and find issues. While I can ask for API credentials for the Graph API, this usually takes a while to get.

But, because most Microsoft portals actually use the Graph API to render the page, we can use a neat trick to grab the Graph API data out of your browser session, so that you can process it with your own scripts.

The first step is to browse to the portal that contains the data you need, and open Web Developer Tools.

I use Firefox, but the same works with Edge and Chrome and just about every browser.

Once you've got the Network tab open, run your query (or hit Refresh), and scroll through the data, so that you've seen everything you need. For example, here's me extracting the information about Guest users in an Entra ID tenancy:

A screenshot of the Azure portal, showing users, with the Web Developer Tools open

Then, right-click in the Network tab, and "Save All as HAR". A HAR file is a JSON document, that exports the entire network history - in other words, it captures the Graph API queries and results.

The next step is to process this HAR into a useful JSON document. For this, we'll use CyberChef.

CyberChef is the "Cyber Swiss Army Knife"; a tool developed by an analyst at GCHQ to allow people to manipulate and analyse data in a simple and repeatable way. The idea is that you create recipes—sequences of operations—for data, that you can save and re-use.

As the HAR file contains all the information about every request the browser saw, we need to filter the information down to just the responses we're interested in.

Because this is JSON data, we're going to use a JPath query to extract the result text for each request, throwing away the other request data. In this example, all the results I want use the /$batch endpoint, so let's create a JPath Expression to select just those requests:

$.log.entries[?(@.request.url == "https://graph.microsoft.com/beta/$batch")].response.content.text

.response.content.text is an escaped string value, so next we need to use Unescape String to get this back to JSON.

Finally, I want these results as a single JSON document, as if I had queried the Graph API directly. I'm going to be lazy, and just use Find/Replace to create the JSON structure.

A screenshot of CyberChef, with a recipe

Awesome, we have usable data! If you're doing this for extracting data from pages that don't use the /$batch endpoint (like Conditional Access Policies), you could probably stop here... but because these are batch results, we need to duplicate the process, to extract just the batch responses.

Starting with another JPath Expression: $[*].responses[*].body.value[*], and then (almost) the same Find/Replace sequence:

A screenshot of CyberChef, with a recipe

And there we are, a single JSON document with all the Guest users!

To save you having to recreate the CyberChef recipe by hand, here's a Link to CyberChef recipe.