{"id":3726,"date":"2026-07-09T16:22:13","date_gmt":"2026-07-09T21:22:13","guid":{"rendered":"https:\/\/microsoftgeek.com\/?p=3726"},"modified":"2026-07-09T16:22:13","modified_gmt":"2026-07-09T21:22:13","slug":"simplify-and-secure-exchange-online-connections-with-azure-automations-managed-identity","status":"publish","type":"post","link":"https:\/\/microsoftgeek.com\/?p=3726","title":{"rendered":"Simplify and secure Exchange Online connections with Azure Automation\u2019s Managed Identity"},"content":{"rendered":"\n<p>Azure Automation is a powerful and flexible tool to automate tasks, and one of my most frequent use-cases is to deploy address book policies in Exchange Online.<\/p>\n\n\n\n<p>Using an ordinary account to connect to Exchange Online should always require MFA, which doesn\u2019t work well in automation scripts. But we have a very nice alternative by using a system-managed identity, which is a special kind of identity in Azure and is managed automatically. So there\u2019s no need to save passwords, fondle with MFA or remembering to replace certificates or secrets before they expire. In order to use this feature you need to set up an Azure Automation account as a managed identity and grant it permissions in Exchange Online.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setup guide: Azure Automation account as managed identity and Exchange Online admin rights.<\/h3>\n\n\n\n<p>Here\u2019s my guide on how to set it up. I\u2019ve created a PowerShell script which does the following<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Log in to Azure<\/li>\n\n\n\n<li>Create a new Resource Group in Azure<\/li>\n\n\n\n<li>Create a new Automation Account in the new Resource Group<\/li>\n\n\n\n<li>Set the Automation Account as managed identity<\/li>\n\n\n\n<li>Log in to Entra using Graph module<\/li>\n\n\n\n<li>Assign permissions in Exchange Online to Automation Account (manage as app and Exchange Administrator)<\/li>\n<\/ul>\n\n\n\n<p><strong>You will need:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PowerShell (preferably PowerShell 7.x)<\/li>\n\n\n\n<li>Az module (installed by the script)<\/li>\n\n\n\n<li>Microsoft Graph Beta module (installed by the script)\n<ul class=\"wp-block-list\">\n<li>At the moment of testing, the \u201cMicrosoft.Graph\u201d module kept failing, but \u201cMicrosoft.Graph.Beta\u201d worked<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>An Azure subscription (Owner or Contributor)<\/li>\n<\/ul>\n\n\n\n<p>You are free to use and modify this script as you wish as long as you respect the Disclaimer in the script synopsis.&nbsp;<\/p>\n\n\n\n<p>&lt;#<\/p>\n\n\n\n<p>.SYNOPSIS<\/p>\n\n\n\n<p>Creates an Azure Automation account as managed identity and grants permissions in Exchange Online<\/p>\n\n\n\n<p>.DESCRIPTION<\/p>\n\n\n\n<p>This script created an Azure Automation account.<\/p>\n\n\n\n<p>Configures the account as a SystemManagedIdentity<\/p>\n\n\n\n<p>Connects to Entra ID<\/p>\n\n\n\n<p>Grants the automation account access to connect to Exchange Online as Exchange administrator.<\/p>\n\n\n\n<p>.NOTES<\/p>\n\n\n\n<p>Author: Per-Torben S\u00f8rensen<\/p>\n\n\n\n<p>Date: 2024-10-09<\/p>\n\n\n\n<p>Version: 2410.09<\/p>\n\n\n\n<p>Requires: Microsoft.Graph.Beta and az module<\/p>\n\n\n\n<p>Tested with: PowerShell 7.4.5<\/p>\n\n\n\n<p>.DISCLAIMER<\/p>\n\n\n\n<p>THIS CODE IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND. ALL USEAGE IS AT YOUR OWN RISK.<\/p>\n\n\n\n<p>The entire risk arising out of the use or performance of this script remains with you.<\/p>\n\n\n\n<p>In no event shall the author be held liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information,<\/p>\n\n\n\n<p>or other pecuniary loss) arising out of the use of or inability to use this script, even if the author has been advised of the possibility of such damages.<\/p>\n\n\n\n<p>The use of this script carries no support from the author, unless otherwise specified. By using this script, you agree to these terms.<\/p>\n\n\n\n<p>#&gt;<\/p>\n\n\n\n<p># Install modules in CurrentUser scope<\/p>\n\n\n\n<p>Install-Module az -scope CurrentUser<\/p>\n\n\n\n<p>Install-Module Microsoft.Graph.Beta -Scope CurrentUser<\/p>\n\n\n\n<p><strong>$rgname<\/strong> = &#8216;ResourceGroupAutomation&#8217; # Name of resource group to create<\/p>\n\n\n\n<p><strong>$location<\/strong> = &#8216;norwayeast&#8217; # Location to store the RG and automation account. Use &#8220;Get-AzLocation | Select-Object DisplayName, Location&#8221; if you need a list of locations<\/p>\n\n\n\n<p><strong>$accountName<\/strong> = &#8216;EXOaccount&#8217; # Name of your automation account<\/p>\n\n\n\n<p><strong>$ModuleName<\/strong> = &#8216;ExchangeOnlineManagement&#8217;<\/p>\n\n\n\n<p><strong>$ModuleVersion<\/strong> = &#8216;3.5.0&#8217;<\/p>\n\n\n\n<p><strong>$tenantid<\/strong> = &#8216;11111111-1aaa-1111-1a1a-aa11aaa11a1a&#8217; # Tenant ID for your Exchange Online environment<\/p>\n\n\n\n<p># Connect to Azure<\/p>\n\n\n\n<p>Connect-AzAccount -AuthScope MicrosoftGraphEndpointResourceId<\/p>\n\n\n\n<p># Create Resource Group<\/p>\n\n\n\n<p>New-AzResourceGroup -Name <strong>$rgname<\/strong> -Location <strong>$location<\/strong><\/p>\n\n\n\n<p># Create Automation Account<\/p>\n\n\n\n<p>New-AzAutomationAccount -Name <strong>$accountName<\/strong> -ResourceGroupName <strong>$rgname<\/strong> -Location <strong>$location<\/strong><\/p>\n\n\n\n<p># Import ExchangeOnlineManagement module<\/p>\n\n\n\n<p>New-AzAutomationModule -AutomationAccountName <strong>$accountName<\/strong> -ResourceGroupName <strong>$rgname<\/strong> -Name <strong>$ModuleName<\/strong> -ContentLinkUri &#8220;https:\/\/www.powershellgallery.com\/api\/v2\/package\/<strong>$ModuleName<\/strong>\/<strong>$ModuleVersion<\/strong>&#8220;<\/p>\n\n\n\n<p># Set up managed identity<\/p>\n\n\n\n<p>Set-AzAutomationAccount -Name <strong>$accountName<\/strong> -ResourceGroupName <strong>$rgname<\/strong> -AssignSystemIdentity<\/p>\n\n\n\n<p><strong>$accountSPN<\/strong> = Get-AzADServicePrincipal -DisplayName <strong>$accountName<\/strong><\/p>\n\n\n\n<p># Connect to Microsoft Graph<\/p>\n\n\n\n<p>Connect-MgGraph -TenantId <strong>$tenantid<\/strong> -Scopes &#8220;Application.ReadWrite.All&#8221;,&#8221;Directory.ReadWrite.All&#8221;,&#8221;RoleManagementPolicy.ReadWrite.AzureADGroup&#8221;<\/p>\n\n\n\n<p># Assign ManageAsApp permission<\/p>\n\n\n\n<p><strong>$AppRoleId<\/strong> = &#8220;dc50a0fb-09a3-484d-be87-e023b12c6440&#8221;<\/p>\n\n\n\n<p><strong>$params<\/strong> = @{<\/p>\n\n\n\n<p>ServicePrincipalId = <strong>$accountSPN<\/strong>.Id<\/p>\n\n\n\n<p>PrincipalId = <strong>$accountSPN<\/strong>.Id<\/p>\n\n\n\n<p>ResourceId = (Get-MgbetaServicePrincipal &#8211;<strong>Filter<\/strong> &#8220;AppId eq &#8216;00000002-0000-0ff1-ce00-000000000000&#8242;&#8221;).id<\/p>\n\n\n\n<p>AppRoleId = <strong>$AppRoleId<\/strong><\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>New-MgbetaServicePrincipalAppRoleAssignedTo @params<\/p>\n\n\n\n<p># Assign Exchange Online Administrator<\/p>\n\n\n\n<p>New-MgbetaRoleManagementDirectoryRoleAssignment -PrincipalId <strong>$accountSPN<\/strong>.Id -RoleDefinitionId 29232cdf-9323-42fd-ade2-1d097af3e4de -DirectoryScopeId &#8220;\/&#8221;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Verify the account and its access<\/h2>\n\n\n\n<p>I strongly recommend that you test the account before proceeding, so now I will use a runbook with a very simple script to verify that the automation account is able to log in to Exchange Online.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Create a runbook<\/h3>\n\n\n\n<p>as of the time I\u2019m writing this post, the ExchangeOnlineManagement module only works in Azure Automation under PowerShell version 5.1 and is unavailable in PowerShell 7.x in Azure Automation. Runbooks must therefore be created with PowerShell version 5.1 to access Exchange Online.<\/p>\n\n\n\n<p>You can either create a runbook through the azure portal directly, or you can use PowerShell script to create it for you. Simply add the following line to the script above if you want to add a Runbook.<\/p>\n\n\n\n<p>New-AzAutomationRunbook -ResourceGroupName <strong>$rgname<\/strong> -AutomationAccountName <strong>$accountName<\/strong> -Type PowerShell -Name Test -Description &#8220;Testing Exchange Online access&#8221;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the runbook<\/h3>\n\n\n\n<p>Now open the new runbook in the Azure Portal, select \u201c<strong>Edit<\/strong>\u201d and \u201c<strong>Edit in portal<\/strong>\u201d to open the editor.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/agderinthe.cloud\/wp-content\/uploads\/2024\/10\/image-1.png\" alt=\"\" class=\"wp-image-1665\"\/><\/figure>\n\n\n\n<p>Add the code below into the editor, remember to replace \u201c<strong>placeholder.onmicrosoft.com<\/strong>\u201d with your real tenantname. Then click on \u201c<strong>Test pane<\/strong>\u201d (this will also save any changes).<\/p>\n\n\n\n<p><strong>$organization<\/strong> = &#8220;placeholder.onmicrosoft.com&#8221;<\/p>\n\n\n\n<p>Connect-ExchangeOnline -ManagedIdentity -Organization <strong>$organization<\/strong><\/p>\n\n\n\n<p>Get-AcceptedDomain | ft<\/p>\n\n\n\n<p>Disconnect-ExchangeOnline -confirm:<strong>$false<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/agderinthe.cloud\/wp-content\/uploads\/2024\/10\/image-2-1024x332.png\" alt=\"\" class=\"wp-image-1666\"\/><\/figure>\n\n\n\n<p>Click \u201c<strong>Start<\/strong>\u201d on the left side and you should see the script starts. The script should end with status \u201c<strong>Completed<\/strong>\u201d and should then display all domain registered in your Exchange Online organization.<\/p>\n\n\n\n<p>As you can see on the screenshot below, the script successfully authenticated to Exchange Online and listed all domain names registered in this organization. Access is confirmed.\u00a0<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/agderinthe.cloud\/wp-content\/uploads\/2024\/10\/image-3-1024x318.png\" alt=\"\" class=\"wp-image-1667\"\/><\/figure>\n\n\n\n<p>And there you have it! A step-by-step guide to setting up Azure Automation to work seamlessly with Exchange Online using a managed identity. By following the steps above you no longer need to worry about automating tasks failing due to MFA rules or expired secrets\/certificates.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Azure Automation is a powerful and flexible tool to automate tasks, and one of my most frequent use-cases is to deploy address book policies in Exchange Online. Using an ordinary account to connect to Exchange Online should always require MFA, which doesn\u2019t work well in automation scripts. But we have a very nice alternative by [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[69,35],"tags":[],"class_list":["post-3726","post","type-post","status-publish","format-standard","hentry","category-azure","category-cloud-computing"],"_links":{"self":[{"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/posts\/3726","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3726"}],"version-history":[{"count":1,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/posts\/3726\/revisions"}],"predecessor-version":[{"id":3727,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/posts\/3726\/revisions\/3727"}],"wp:attachment":[{"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3726"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3726"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3726"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}