There’s a clear lack of love for the Exchange group and the Graph API, particularly when it comes to managing mail-enabled groups. Currently, the Graph API can only handle simple read commands for mail-enabled groups, which is a pain when dealing with real-world scenarios.
Let me explain.
When you create a user on-premise that syncs into Entra ID (or even a cloud-only user), something happens behind the scenes that synchronizes the user from Entra ID into Office. I’m not entirely sure what that process entails, but it directly impacts managing users with Exchange. The user doesn’t exist in Exchange until this sync completes. If you attempt to run a Get-User command on the newly created user before this sync finishes, you’ll encounter the following error:
error:Ex6F9304|Microsoft.Exchange.Configuration.Tasks.ManagementObjectNotFoundException|The operation couldn't be performed because object '<upn>' couldn't be found on '<serverName>.PROD.OUTLOOK.COM timestamp: <timestamp>
Most of the time, the sync finishes within seconds after creating a user. However, in some cases, it can take hours. Microsoft support informed me that it could take up to 24 hours for the sync to complete — a frustrating revelation. I was aiming for real-time automation, where users would be added to the correct mail-enabled groups as soon as they’re created. But since the Graph API doesn’t support user management in this context, I had two options: either use the portal or the Exchange Online PowerShell module.
Since this process needed to be automated, I chose to use the Exchange Online PowerShell module, setting up an Azure PowerShell Function. Initially, I considered adding a loop to check periodically if the user existed, but running into the Azure Function consumption plan’s HTTP timeout (230 seconds) quickly proved this approach impractical.
Next, I explored Azure Durable Functions. My thinking was that I could use async polling to check when the user was successfully created, then proceed to add them to the mail-enabled group. This seemed like a solid solution to the sync timing issue. However, another obstacle emerged: the durable function would throw an exception if the user didn’t exist, leading to additional retries. With multiple retries, I noticed the function running out of disk space.

It turns out that each time the durable function executed, it loaded the Exchange PowerShell module into a temporary directory. This caused the function to quickly run out of disk space, but I couldn’t directly view or manage the temporary storage because it’s handled by Microsoft. After some digging, I found a set limit on temporary storage for Azure Functions, which is detailed https://learn.microsoft.com/en-us/azure/azure-functions/functions-scale

I needed to track my temporary storage usage, so I headed to the “Diagnose and Solve Problems” section in my App Service blade, and under “Best Practices,” I found the “Temp File Usage On Workers” option. Sure enough, I could see a spike in usage, which caused the out-of-disk-space exception. At this point, I could switch to an app service plan, but that would negate the cost savings of using a consumption plan. My tests showed that the temporary usage leveled off around 1.5 GB.


The above picture shows the temp usage leveling off with a basic app service plan. I proved it could be done, but I want the cheapest path possible.
So, back to the drawing board. The most cost-effective solution I came up with was returning to a regular Azure Function and utilizing queues. I’d drop a message onto a queue and periodically check if the user existed. Once confirmed, I’d add them to the group, place a message on another queue for further processing, and notify the user.
