Managing DLs through Azure runbooks
I will try to go through the pain points of managing Distribution lists in Microsoft.
It has been a long outstanding issue in Microsoft that, they don't allow managing their exchange module via graph apis or any other apis for that matter. So you have to manage it via their UI or Powershell.
Coming to how you can potentially automate exchange management or any such use cases where Microsoft doesn't have apis but allows you to manage via Powershell. We can create runbooks on Azure automation accounts which can do these management actions and call it via a webhook to trigger it whenever required.
For eg: When you want to add a user to a DL, just call the webhook with the DL name and user principal.
There are numerous tutorials on this all around the web, but you might get stuck on what kind of identity to use, how to give permissions, and how to call it remotely.
Sharing a few here in case it helps
- https://www.damobird365.com/add-user-to-distribution-list/
- https://learn.microsoft.com/en-us/powershell/exchange/connect-exo-powershell-managed-identity?view=exchange-ps
- https://www.shudnow.io/2022/07/22/azure-automation-runbooks-and-connecting-to-exchange-online/
- https://practical365.com/use-azure-automation-exchange-online/
- https://stackoverflow.com/questions/74213208/connect-exchangeonline-unauthorized
The setup
Step 1 (Creating an automation account)
Create an Azure automation account (Microsoft gives you 200$ free credits)
Step 2 (Creating a Runbook)
Next, you need to configure a Powershell (7.2 version) based runbook that has ExchangeOnlineManagement & ExchangePowerShell modules.
First Create a runbook for writing the script
param(
[object]$WebhookData
)
try {
"Logging in to Exchange..."
Connect-ExchangeOnline -ManagedIdentity -Organization atomicwork.onmicrosoft.com
"Adding user..."
$webhookBodyObject = (ConvertFrom-Json -InputObject $WebhookData.RequestBody)
Write-Output "Hello $webhookBodyObject"
Write-Output $webhookBodyObject.email
Write-Output $webhookBodyObject.distribution_list_id
Add-DistributionGroupMember -Identity $webhookBodyObject.distribution_list_id -Member $webhookBodyObject.email
"User Added"
} catch {
Write-Error -Message $_.Exception
throw $_.Exception
}
You can use this code if your end goal is to add user to a DL.
Install 2 modules ExchangePowerShell & ExchangeOnlineManagement
Go to Automation account -> Modules -> Add module -> Browse from gallery -> Search ExchangePowerShell and hit select.
Repeat for ExchangeOnlineManagement
Now you have the script and runbook read. Now all you need is to give access for the automation accounts identity to access your exchange.
Step 3 (Giving access)
Assigning a role to automation account
Pre final step : Microsoft also expects the service principal of the automation account to have certain permission on top of the role assigned, this can be done with powershell(if you are using mac you can still use powershell — https://formulae.brew.sh/cask/powershell)
- Get the managed identity id (go to enterprise apps, uncheck Application type = Enterprise Applications), search for your automation account to get its object id. managedIdentityObjectId in the upcoming script
- Similarly search for Office 365 Exchange Online and copy the object id for serverServicePrincipalObjectId in the upcoming script or run Get-Get-MgServicePrincipal -Filter “DisplayName eq ‘Office 365 Exchange Online’”
Get the App role ID for the Exchange.ManageAsApp permission (either by api or through powershell)
https://graph.microsoft.com/v1.0/servicePrincipals/{{theObjectId you got in prev step for office 365}} -> grab the id Exchange.ManageAsApp
currAppRoleId in the upcoming script
Once installed poweshell and have the following values run the following commands to assign Office 365 Exchange Online, Exchange.ManageAsApp permission
Install-Module -Name Microsoft.Graph.Authentication -Repository PSGallery -Force
Install-Module -Name Az.Accounts -Repository PSGallery -Force
Install-Module -Name Microsoft.Graph.Applications -Repository PSGallery -Force
Connect-MgGraph -Scopes Application.Read.All, Application.ReadWrite.All,AppRoleAssignment.ReadWrite.All,Directory.ReadWrite.All
New-MgServicePrincipalAppRoleAssignment `
-ServicePrincipalId $managedIdentityObjectId `
-PrincipalId $managedIdentityObjectId `
-ResourceId $serverServicePrincipalObjectId `
-AppRoleId $currAppRoleId
End result would be something like
Thats it, Now you have an automation account, runbook with a script and required modules, permission for the automation accounts to perform actions on Exchange.
Step 4(the final step — webhooks)
Expose a webhook for the runbook script that was created, so that it can be invoked from other places.
This seems like a cumbersome setup, but once you have done this initial setup, life becomes easier, All you need is to create a webhook
Time to try it out
Go to your favourite api tester app (postman) or terminal and run the curl
curl --location 'yourwebhookurl' \
--header 'Content-Type: application/json' \
--data-raw '{
"email": "youruserPrincipal",
"distribution_list_id": "your dl id"
}'
Run this, and you can see that in few seconds the runbook runs and the user gets added to dl, Runbook UI gives you visibility of the jobs that ran (look at the jobs tab, click on the runs and see the output, errors etc)
Now u can manage any such action by creating multiple such scripts and calling it via webhooks
- Adding someone to DL
- Removing someone from DL
- Changing owner of DL etc