Using and Migrating to the Microsoft Graph People endpoint - For Equipment Mailboxes, Resource properties and the Graph userpurpose property
A couple of weeks back I wrote a post around contact management and using the Exo Cmdlets as a workaround for some Graph Endpoint experiences. In this post I’m going to go into a more native exploration of the Graph people endpoint, give a few hacks around some of the limitations and talk about some of the pitfalls of trying to manage either a new application design or migration from EWS to this new endpoint.
The Two
Graph currently has two endpoints for searching for objects/recipients in the Global Address List the people endpoint and the Search endpoint . Let’s talk about the Search Endpoint first as it’s been in preview since 2021 and while the Search endpoint in the Graph has had some active development and improvements this hasn’t extended to the people/contacts side so it looks like it was a good start and has a few use cases but for what I’m going to talk about it isn’t usable and the documentation isn’t accurate in a number of places. So the people endpoint is the most usable especially if your migrating from EWS as it matches more closely with resolveName and the way Mapi works. Note there are some application scenarios where search is better more on the new Application side rather then the migration one.
Finding Equipment Mailboxes and/or Room mailboxes with specific resource custom properties.
Equipment, Meeting Rooms and now Teams Meeting rooms mailboxes are an everyday application that you may turn to an API to find. Especially if you have the need to replicate the address book feature or resource scheduler from Outlook in your application.
UserPurpose Property in Graph (kind of useful in certain instances)
The UserPurpose property in the MailboxSettings endpoint can tell you the purpose of a particular DirectoryEntry (or Mailbox). So being able to filter the users endpoint in Graph by one of these types would be great but you can’t do this. When you have a medium to large Entra directory this makes creating good applications (that perform well and use minimal resources) difficult. You also can’t access the UserPurpose property of any object other then your own (currently authenticated user) if your using Delegate Access so this property is limited to when you are using Application tokens/permissions. If you have a large volumes of object you need to access this property on requires you to use batching. My experience even doing this at the very limited 20 items a batch is that its not particularly reliable either (eg certain object will return 500 and gateway errors that can be resolved with a retry) so dropping it down to 10 items per batch seems to make it more reliable (DYOR). What this means in real terms is that fulfilling a “replicate the address book feature or resource scheduler from Outlook” feature request in an Application isn’t easy to deliver using Graph API at scale in the way Outlook does (which doesn’t use the Graph).
Searching using the People Endpoint
While using the User’s endpoint and a filter would have been the optimal solution we now had to switch to trying the People Endpoint. The People Endpoint does have filters for certain person SubTypes which can includ personalContact, Room Mailboxes but it also doesn’t support Equipment Mailbox as a subtype. It also doesn’t support using Filters when your doing a Directory only search which you use the X-PeopleQuery-QuerySources header for. Eg if I wanted to listed Unified Groups
The first request should have returned the unified groups from the Directory a useful feature in a AB app.
Target the Directory
By default the People endpoint in Graph only searches the Mailbox so to make it also or only search the Directory you need to use the X-PeopleQuery-QuerySources header and set it to “Directory” for directory only searches or “Mailbox,Directory” for mailbox and directory searches.
Fuzzy Searches to the Rescue (kind of)
ANR (Ambiguous Name Resolution) has been around in Active Directory, PowerShell, Outlook clients and Exchange for a long time. Its the algorithm that allows you to enter a partial name or different attributes and have it resolved to a particular directory Entry. In EWS this gets surfaced as ResolveName in the People endpoint in the Graph it seems they just renamed it Fuzzy Search (maybe after a big night on the sauce) as it works pretty much the same way. The actual algorithm in terms of what properties are searched and what parameters is a little fuzzy but to understand this its best to look at the address book using a MAPI editor like MFCMapi or OutlookSpy. This gives you the raw level view of what ANR does have access to (behind the API opaqueness). eg
and for a room with Resources
So the important point I’m trying to highlight is that there are properties included in the Fuzzy search to return a Mailbox if its an Equipment mailbox and also there is coverage for custom resource properties which have been around for a while and are quite useful. This means to find Equipment Mailboxes in an Microsoft 365 Tenant you can do a fuzzy search like this in the PowerShell Graph SDK
Get-MgUserPerson -UserId user@domain.com -Search equipment -Top 100 -Headers @{"X-PeopleQuery-QuerySources"="Directory"}
in my tenant it returns the following
Searching is one thing validating is another - Not everything is an Equipment Mailbox
Because this is working through ANR its also going to find mailboxes where equipment is in the name of the Mailbox. In my example the first entry in a Room mailbox the is named Equipment Mailbox. This is where the userpurpose property would come in handy. There is a PersonType property which has a Subclass that does let us know that the Equipment Room mailbox is a Room mailbox but it doesn’t tell us that the other 3 mailboxes are Equipment Mailboxes eg
So it’s possible that within the last 3 entries that they could be SharedMailboxes or Usermailbox with equipment in a searchable property. If you can use AppTokens then you can use the userpurpose property in batches to make this finally work. I put together a script to demonstrate this which is located here https://github.com/gscales/Powershell-Scripts/blob/master/Graph101/GraphSDK/SearchPeopleWithBatchUserPurpose.ps1 the output of this script looks like
To use this script you need to have a Graph Connection with the following scopes
Connect-MgGraph -scope "People.Read.All,User.Read.All"
To highlight this a little further say if I create a new Shared Mailbox in my tenant and named it Shared Equipment Mailbox I would then get this output with my script.
Note for a Shared Mailbox the person SubClass is OrganizationUser while the userpurpose is Shared.
The limits of the People Endpoint
There are a few limitations around the people endpoint the first is the number of results it will return is limited. ResolveName in EWS was limited to 100 result but the People Endpoint tops out at 50 if your searching against the directory. If you want to see an example of an infinite loop try running this in the Graph PowerShell
Get-MgUserPerson -UserId gscales@datarumble.com -Top 1000 -search "SMTP:" -Headers @{"X-PeopleQuery-QuerySources"="Directory"} | select DisplayName,@{n="PersonSubClass";e={$_.PersonType.Subclass}}
Custom resource properties
I made a brief mention of custom resource properties above and they are available in ANR so for my mailbox where i have a coffeemachine resource property i can use the following
But you can’t validate resource properties against anything that is returned in any of the Graph endpoint (to be fair you couldn’t do this with EWS either just with Mapi against the address book).
Final word if you are migrating from EWS
If you are only using Resolve name in EWS you should be able to hit the majority of what it did with the people endpoints. If you look at the calls that something like Outlook on the Web makes it’s a client app running as a user that is able to get msExchRecipientDisplayType for all the objects in the Global address list so it has some advantages from it’s private API’s over what you can do publicly. This can be a problem if you try to replicate what Outlook does so you may need to think a little laterally eg schema extensions to tag the resources the way you want or replicate the directory outside of Azure and classify as you want. The only issue with those type of solutions is they aren’t turn key applications which can be a critical factor when developing this type of stuff.