Graph API detect if user has an O365 mailbox

As part of something I was trying today I wanted to find out via Graph API whether a particular user has an O365 mailbox or not. There’s probably better ways to do this but I couldn’t find any and finally came up with the following.

The Graph API can return the mailboxSettings for a user (see the docs). This is not returned by default, one needs to use the select operator. I noticed that for a user who has a mailbox I get the following:

Whereas for those with on-prem mailbox I get this:

I thought I could put this into a try/ catch block to maybe identify mailboxes that are on-prem or in the cloud:

That doesn’t work unfortunately. The error isn’t captured in the try/ catch block. (Update: this actually works, see below).

Next I thought let me try invoking the API directly.

After poking around I found that calling this URL https://graph.microsoft.com/v1.0/users/<upn>/mailboxSettingsreturns output like this:

Put that in a try/ catch block and $_.Exception has the following:

Ok… digging in deeper I get that $_.Exception.Response.StatusCode has NotFound for an on-prem (or non-existent) mailbox and Forbidden for one that exists (forbidden because my account doesn’t have rights to view mailboxes; if you were trying with a different account you might get something else… so beware). Thus we have the following:

As you can see I took things one step further and figure that if a user doesn’t have a mail attribute then the NotFound message just means they don’t have a mailbox. (Could have just done this check first before the Graph query now that I think about it…)

I have no idea if this is the “correct” way to do this or I am just complicating matters, but here it is.

Updates:

Update 2:

Every now and then you Google on something, forgetting you have posted about this in the past, and come across your own blog. Can’t beat that feeling! :)

My first attempt via Get-MgUser works, just that I need to add -ErrorAction Stop.

It’s probably for the best that I didn’t go down this route though as it is not very good looking. I like what I stumbled upon eventually using the status code. Here’s a revised variant of that:

Update: Follow-up post here.