Under the Hood, Pt. 3: M365 Apps Admin Center

Under the Hood, Pt. 3: M365 Apps Admin Center
Photo by Markus Spiske / Unsplash

Part 3 of my "Under the Hood" series looks at the M365 Apps Admin Center, capabilities, reporting, authentication, and more undocumented API fun!

Now with an extra bonus of a GitHub repo!


Config dot Office dot what?!

For the uninitiated, let's go from the top.

The config.office.com portal is by far the most underrated portal around, but I'd go as far as saying that 95% of people I speak to don't even know it exists, but there's so much cool stuff available, look!

config.office.com menu

Let's take a high-level look at the options available to us here.

πŸ“ŽServicing Profiles

The purpose of these is to significantly streamline how you patch your M365 Apps for Enterprise/Business. Amazing reporting and two-click rollback in case of issues, it also allows you to configure which channels you want to pull into standardisation (currently only Monthly Enterprise is supported but Current and Semi-Annual are coming soon), rollout waves a-la WUfB Rings, update deadlines and even exclusion dates in case your finance department can't risk losing business continuity over an audit for example.
If you're not using Servicing Profiles, you're making your lives harder. Do it.

Servicing Profiles

βš™οΈDevice Configuration

Device Configuration is the newest iteration of the Office Customisation Tool, allowing you to configure a custom install XML to feed into the ODT (or even better, create a link and use the marvellous M365Apps scripts by MSEndPointMgr to Win32 your installs). You can theoretically use this as a pseduo Change Control mechanism to keep track of your installs

Device Configuration

πŸ›‘οΈPolicy Management

Managing policies for the M365 Apps is a curious one as I've had very few customers approach me wanting to implement them, mostly due to concerns about impact, however there are now multiple ways of doing this; Via config.office.com, Apps>Policies for Office Apps in Intune (which is just an iFrame of config.office!), Settings Catalog, but now also the Security Baseline in Intune.
One thing to note about the config.office approach is that while the above two options work with both Apps for Enterprise and Apps for Business, Cloud Policy is only compatible with Enterprise (or at least from testing with Business, policy is delivered but not enforced).
Word of warning, there are a lot of policy options available here, I wouldn't recommend going and applying stuff with wild abandon.

Cloud Policy

πŸ₯Health

Bundling the next section into one, there are multiple bits of data available here: M365 Apps Health - Reports showing performance-related metrics, sessions and advisories to resolve issues.
OneDrive Sync Health - OneDrive-focused reporting showing sync errors, Known Folder Move status and sync client version as well as specific issues.
Security Update Status Report - High-level report of up to date/not up to date status of M365 Apps, and you can even set a goal appropriate to your business' update targets (for example 14 days here in the UK for Cyber Essentials compliance).

Health - Security Update Status

πŸ“ŠInventory

Finally, there's the Inventory, a global view of every single device with data on architecture, build, update channel, and usage of COM/VSTO add-ins and macros!

Inventory

All of the above are completely free, have zero user impact to enable, and provide incredible data-driven insights to any device estate.


The Problem

All of that data is amazing, but there's a key problem right now:

It's all trapped behind the portal UI.

For those of us who work in Managed Services, or even just those who want to create custom, centralised reporting dashboards through something like PowerBI, being able to programmatically view data through API's like Graph is incredibly important.

Something like WUfB Reports parses Windows Update telemetry back to a Log Analytics Workspace for easy reporting, and the same principal can be used for custom log ingestion, such as the marvellous Enhanced Intune Inventory by the team at MSEndpointMgr. You could even utilise something like a Logic App to hit an API on a schedule and store the data for easy visualising.

But enough of the high-level, let's go Under the Hood!


API Time

I think it's important that I prefix this section with the following:

⚠️
Information below can be easily obtained using Dev Tools and something to do API calls, however it is meant for educational purposes only.
You can break things by doing stupid stuff and these are all completely undocumented API's.

πŸ”Authentication

What with these API's being undocumented, access (as far as I've been able to determine at least) isn't as straightforward as elsewhere within Azure, and seems to be entirely witchcraft and voodoo. As mentioned in my previous Under the Hood posts, I'm not good at this stuff, but I do find going down the rabbit hole exciting!

Authentication starts off as you'd expect. Signing in through the UI requests the standard OpenID configuration:

https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration

Followed by a POST to the following URL to request a bearer token:

https://login.microsoftonline.com/common/oauth2/v2.0/token

Curiously, the payload for the token request includes the following:

client_id: 3cf6df92-2745-4f6f-bbcf-19b59bcdb62a
scope: https://config.office.net//.default openid profile offline_access

Using the AAD token viewer at jwt.ms with the returned bearer, I was able to identify the AppID of the app in the authentication request: 3cf6df92-2745-4f6f-bbcf-19b59bcdb62a, which correlates to the Office 365 Client Admin Enterprise Appplication:

Following the token retrieval, there's a call to https://clients.config.office.net/appConfig/v1.0/ShellService/GetShellInfo which I discounted at first because it looked to just be loading all of the App Launcher stuff you get when going to any other part of O365, which it is, but I believe this to be for more than one purpose here as I began to notice other token requests depending on where you are in the UI. These ones have a different user_impersonation scope in the response which, when searched in AAD, point to multiple other AAD App Registrations:

O365 Client Admin App sign-in logs

This inter-weaving of App Registrations looks like it could be being coordinated by the TokenFactoryIframe, something I can only describe as "middleware" which seems to dole out appropriate rights via user impersonation when requested, but what it's achieving is essentially communicating with the various API's via a virtual shell session.

For laughs, I wondered if it would be possible to create an Azure Logic App, a managed identity, provide that identity the Office Apps Administrator AAD role, and be able to access the API's "sans-user".

It wasn't. I assume down to the fact that a managed identity isn't an actual user, though it could equally be down to my sub-par skills in understanding authentication flows and Logic Apps, so the jury is still out on that one...

🌐Endpoint Investigations

Documenting all of this was tough, and getting it all into a way that was acceptable in blog format was impossible, so instead I put it all in a GitHub Repo!

GitHub - SkipToTheEndpoint/M365AppsAPI
Contribute to SkipToTheEndpoint/M365AppsAPI development by creating an account on GitHub.

I've tried to give as much info on the different endpoints, as well as some example JSON responses from them so you can see the sheer wealth of information available within them. HTML isn't my forte so apologies for any difficulties navigating the pages with big JSON responses. If anyone's got a better way of visualising it all, do let me know!

β›”Warnings!

While messing around with API's shouldn't let you mess with things to the point you break them, and that might generally be the case if one was actually documented, we're not dealing with that here. Needless to say, I took a bullet so you don't have to.

I was curious to see if it was even possible to automate something, despite the fact that even accessing the service seems to be behind some magic. The easiest (and most helpful) thing that came to mind was to programmatically configure a Servicing Profile.

Firing up a completely new, untouched tenant, I observed the calls being made.
Looking at the Profiles endpoint, it was pretty easy to decipher that while the Servicing Profile had been given a GUID, it wasn't active:

{
    "id": "%SPGUID%",
    "active": false,
    "profileState": 0,
    "profileType": 0,
    "rolloutPipeline": 0,
    "targetChannel": 4
}

On top of that, the SP Rules endpoint was (understandably) throwing a 404 response, at least initially, though that did seem to mysteriously come right. I compared the Profiles response against a tenant that had a Servicing Profile already configured:

{
    "id": "%SPGUID%",
    "active": true,
    "profileState": 400,
    "profileType": 0,
    "rolloutPipeline": 0,
    "targetChannel": 4
}

Easy, right? I have the SP GUID, so I can hit https://clients.config.office.net/ServiceProfile/v1.0/%SPGUID% with and update the active property to true and the profileState property to 400 (whatever that means).

So I did. And it failed. But I got a useful error!
I'd taken a guess that I might need to PATCH, but it wasn't having any of it.
So I tried again, this time with a PUT.

And it worked!

Sort of.

Well. At least as far as Postman was concerned it did. What actually happened was the profile was showing as active via the API, it had default rules configured, it looked like it was running fine.
But it wasn't. Going back to the UI, every time I navigated to the Servicing Profile page it threw back the initial configuration wizard. I could go through it, hit complete, seemingly get a success and... Be thrown back to the initial configuration wizard again.

I'd caused an infinite configuration loop. Even worse, the profile just didn't seem to work and never picked up any devices to service. I'd broken it completely.

Categorically do not do this (or probably try any PUT/PATCH requests) to these API's in your production environment. I'm sure someone at Microsoft would be able to rectify it, but getting there might be a task.


Lessons Learned

So what did going down this somewhat interesting but largely pointless avenue actually prove?

It proves that there is a massive amount of information available within the M365 Apps Admin Center which can be incredibly helpful for making data driven decisions, or even just being able to report on things like patch compliance of your Office Apps, but if one thing is clear, many people like the ability to ship this data to somewhere else (Log Analytics, PowerBI etc.) to be able to do things like create custom reporting or alerting.

Right now, this is completely impossible with this data, and it takes an actual human being time and effort to manually dive into the UI to extract any helpful information rather than being able to look at a centralised report.

I'd really like to see that change, and have the data made available programmatically (ideally with some accompanying API documentation) outside of the UI.

James Robinson

James Robinson

With 20 years of experience, James is a Principal Consultant specialising in Modern Workplace and End User Compute technologies, with a focus on Modern Management and Cloud-Native endpoints.
Brighton(ish), United Kingdom