When you set up a third-party app to talk to Exchange (in Enterprise Applications or App Registrations), Azure lets you set permissions to ALL mailboxes and calendars. You grant the app Mail.Read or Calendars.ReadWrite, and suddenly that app has permission to poke around in every single mailbox in your organization (yep, even the CEO).
Application Access Policies are available, but those only limit the mailboxes your app has access to without being able to limit the type of access to those mailboxes.
RBAC for Applications in Exchange Online gives us the ability to grant different permissions to different mailboxes and is meant to replace Application Access Policies.
The Best of Both Worlds
Let’s say you have an app running on your website that checks your sales team’s calendars and sends an email from your marketing mailbox with a calendar invitation that books the first opening on a sales member’s calendar. Your app will need Mail.Send permission to just the marketing team mailbox and calendar.readwrite for your sales team. It is a *REALLY* good idea to only give specific permissions to specific mailboxes and/or calendars that are needed. What’s great is that it works in addition to the Graph API access you’ve already granted. Think of it as a double-lock system. Entra ID gives the app the "key" to the building, but Exchange RBAC decides which "rooms" (mailboxes) that key can actually open. There is no GUI for RBAC for Applications, so if you’re ready to use some powershell, let’s lock down our apps!
I’ll step through each of these, but if you just want a high level view, here’s what we’re going for.
When I first tried this out, the PowerShell versions and modules I was using to go through this process were in a weird state where the new authentication process required PowerShell 7, but the Exchange tools were using older calls requiring PowerShell 5. Please believe me when I say verifying your versions of PowerShell, Microsoft.Graph, and ExchangeOnlineManagement are as important as understanding the RBAC process. With Microsoft constantly updating these tools, it’s a good idea to check for updates regularly as well. Please save yourself from my pain!
The "Pre-Flight" Checklist: PowerShell Requirements & Installation
If you’re running Windows, there’s a good chance you’re toggling between Windows PowerShell 5.1 (part of the OS) and PowerShell 7.x (the standalone application).
Windows 11 running minimum versions of PoSh 5.1.26100.7920 or 7.5.4 will set you up for success. I’ll take screenshots of this process side by side (5 on the left, 7 on the right) so you can see the action.
Step-by-Step Installation
Quick note on -Force & -AllowClobber switches:
Close your administrative window and open a regular powershell window before performing these next steps. First, you’ll need to grab some info from the Entra ID side. Specifically, you need the AppId and the ObjectId.
GUI:
Be sure to get this info from the Enterprise Application section, NOT the App Registrations
In the GUI it looks like this:
THIS GIVES YOU THE WRONG OBJECT ID:
CLI:
You can also use the Microsoft Graph PowerShell module to find these quickly:
!!! Important Note on Assembly Version Clash !!! (THIS MAY SAVE YOUR SANITY)
Shared identity libraries can cause RuntimeBroker errors, NullReferenceException, or a MissingMethodException.
In Powershell 7, connect to ExchangeOnline BEFORE connecting to MgGraph to use the same window, otherwise, open two separate windows to avoid the clash.
In Powershell 5, you’ll need to open two separate windows, one to connect to Exchange, and another to connect to MgGraph
PowerShell
# Connect to Graph
Connect-MgGraph -Scopes "Application.Read.All"
# Find your service principal
Get-MgServicePrincipal -Filter "DisplayName eq 'YourAppName'" | Select-Object DisplayName, Id, AppId
# Make it easy on yourself and set some variables
$ObID = get-mgserviceprincipal -filter "DisplayName eq 'App That Needs Exchange Access'" | Select-Object Id
$AppID = get-mgserviceprincipal -filter "DisplayName eq 'App That Needs Exchange Access'" | Select-Object AppId
Our prep is done! Now that you have everything you need, you can start working with Exchange Online.
***NOTE***
“get-mgserviceprincipal” is part of the Microsoft.Graph module
“New-ServicePrincipal” is part of the ExchangeOnlineManagement module
Although they’re referring to the same information, we need to define our principal (or app) in Exchange so it knows what to apply the RBAC permissions to.
Step 1: Create the Service Principal Pointer
After connecting to Exchange, we’ll tell it that this Entra app exists.
Connect-ExchangeOnline
New-ServicePrincipal -AppId <Your-App-ID> -ObjectId <Your-Object-ID> -DisplayName "My Scoped App"
( <Your-App-ID> would be $AppID if you set the variable, otherwise it’s the Application ID from the GUI )
( <Your-Object-ID> would be $ObID if you set the variable, or the Object ID from the GUI )
As you can see, even if you try to set it up with a different name, you can only create one service principal per app ID.
Step 2: Define Your Scope
This is where the magic happens. You can create a "Management Scope" to filter exactly which mailboxes the app can touch. For example, if you want to limit access to users in a specific department, you would do something like the following. You can create multiple management scopes to handle mailboxes and/or calendars, and you can use various filters to use other aspects of the Exchange objects.
New-ManagementScope -Name "Marketing Mailboxes" -RecipientRestrictionFilter "Department -eq 'Marketing'"
Step 3: Make the Assignment
Now, tie it all together. You assign a specific "Application Role" (like Application Mail.Read) to your Service Principal, restricted by the scope you just made.
New-ManagementRoleAssignment -App <Your-Service-Principal-Object-ID> -Role "Application Mail.Read" -CustomResourceScope "Marketing Mailboxes"
As with anything in the world of IT, it’s rarely a straight-line process. I ran into a couple of head-scratchers while testing this out that might save you some hair-pulling:
Moving to Application RBAC might feel like an extra step, but the security payoff is massive. In an era of OAuth phishing and credential theft, "least privilege" isn't just a best practice—it's a survival tactic.
Next time you’re onboarding a new tool that asks for "read everything" permissions, take five minutes to set up an RBAC scope. Your future self (and your security auditor) will thank you.
LookingPoint offers multiple IT services if you’re interested. Want more information, give us a call! Please reach out to us at sales@lookingpoint.com and we’ll be happy to help!