The Reality of Graph API for Exchange Distribution Lists: Still Tied to PowerShell

The Reality of Graph API for Exchange Distribution Lists: A Hard Lesson in Limitations

Some time ago, I was tasked with syncing a membership list in Dynamics 365 with Exchange Distribution Lists. For reasons I won’t go into, using the marketing component of D365 was a no-go.

I had thought, yeah MS Graph can handle that, So, like any good techie, I double checked with a a quick Google search. “Graph API can manage distribution lists” – Yep, it sure can. Sweet.

A quick setup, and we thought we were on track. Microsoft Graph has conditioned many of us to believe everything in Microsoft 365 can be handled under its roof.

This time, however, that assumption was dead wrong.

We set up a couple of triggers, handled authentication, and made a few API calls, expecting everything to work seamlessly. Turns out, NOPE! While Graph API allows us to create and delete Distribution Lists, that’s about as much management as we get on this front.

The Hard Limits of Graph API

Once we started testing, the issues became clear:

  1. No Direct Membership Management
    • Graph lets you work with Microsoft 365 Groups, but when it comes to traditional Exchange Distribution Lists, adding or removing members is out of the question.
  2. Lack of Detailed Group Information
    • Metadata retrieval for mail-enabled security groups and standard distribution lists is unreliable at best. Expanding groups to get a full member list? Good luck with that.
  3. No Delta Queries for DLs
    • Unlike many other objects in Graph API, Exchange Distribution Lists do not support Delta queries, making change tracking a pain.

Back to the Old Reliable: PowerShell

With Graph API falling short, we had no choice but to fall back on trusty old PowerShell, which, despite its quirks, just works:

  • Modify Distribution List Memberships (Add/Remove members, set owners)
  • Expand Distribution Groups to reliably fetch all members
  • Manage Hidden Membership Groups
  • Handle Dynamic Distribution Lists

Now we don’t want waste human time manually running the scripts, so we set up an Auzre Function to run a few things to it all.
Power Automate Flow seemed a logical option as it can trigger a http call upon a change event to a member list or contact. Az Func steps up connects to D365 with its API and bounces the changes to Exchange.

But. No. Per change processing is going to be a problem. Exchange Online PowerShell can’t operate with multiple sessions. Subsequent calls will take over the previous session. this can lead to all sorts of oppsies happening.

We need to instead use Deltas from dynamics on a timed interval and do away with any per change trigger. We then connect to exchange, do all of the changes and exit out the session in time for the next instance to run.

From there its pretty simple, using the Exchange Online PowerShell module, commands like:

PowerShell
Get-DistributionGroupMember -Identity "DL Name"
Add-DistributionGroupMember -Identity "DL Name" -Member "user@domain.com"
Remove-DistributionGroupMember -Identity "DL Name" -Member "user@domain.com"

But there’s another issue: the email may not even exist in Exchange. Before adding a member, we need to verify their recipient status. Sometimes, they might not exist at all, in which case we must create it, a mail contact would typically suffice. Other times, they could already be in Exchange, but as a different type of recipient.

Handling Multiple Exchange Recipient Types

The process looks like this:

  1. Check if the recipient exists in Exchange:
    • If not, create a mail contact for them.
  2. If the recipient exists, check for multiple entries:
    • Users may have multiple records (e.g., a guest account and a contact record with the same email).
    • Sort recipients in the following preference order:
      • Mail account (if they have an active Exchange mailbox)
      • User mailbox
      • Guest account
      • Mail contact
  3. Add the recipient using Object ID:
    • Since multiple recipients can share the same email, adding by email address will fail if there is a duplicate in the system.
    • Using the Object ID ensures we add the correct recipient.

Once all that is figured out, we then pull delta lists from Dynamics 365, track changes, and add or remove users accordingly from Exchange. This ensures that memberships remain in sync while handling all possible recipient types in Exchange.

Lessons Learned

This experience has taught me a few key things:

  • Always triple-check exactly what Graph API can and can’t do before assuming it covers everything.
  • PowerShell is still essential, especially when working with legacy Microsoft services.
  • If necessary, reverse-engineering PowerShell modules to understand their backend calls can reveal ways to replicate functionality through custom APIs.

What’s Next?

Microsoft is expanding Graph API’s capabilities for Exchange, but for now, Distribution List management is still behind. Until Graph provides full parity, PowerShell remains king.

Leave a Comment

Your email address will not be published. Required fields are marked *