Using the Exchange.ManageAsApp Permission with Exchange Online PowerShell
Updated 7 December 2022
With the addition of support for managed identities in V3.0 of the Exchange Online management PowerShell module, developers might be more interested in creating Azure Automation runbooks that use the Exchange Online cmdlets to process data like mailboxes. In this discussion, when I refer to a managed identity, I mean a system-assigned managed identity working within an Azure Automation Account. Essentially, a managed identity is a service principal used to access Azure resources that Azure manages automatically. No access is available to the credentials for the managed identity. Like the service principals for other apps, managed identity service principals can hold permissions to allow them access to resources like apps.
As an example, it’s now easy to connect to Exchange Online in a runbook with a command like:
Exchange Online connects using the managed identity owned by the Azure Automation account that’s executing the runbook.
As noted above, before it can do anything interesting after connecting, the managed identity needs permissions. The essential permission for Exchange Online is Exchange.ManageAsApp, which allows an app to run Exchange Online cmdlets as if the app was an administrator account. Service principals for registered apps and managed identities both need this permission to do useful work with Exchange Online cmdlets.
At the same time, Microsoft said that they “removed the Exchange app permission from the Azure portal.” The Exchange.ManageAsApp permission is one of the permissions in the Office 365 Exchange Online API. Microsoft’s action didn’t remove the ability to assign the permission to apps in the Azure AD admin center. It just made the process a little harder.
Assigning Exchange.ManageAsApp
To assign the Exchange.ManageAsApp permission to a registered app, select the app in the Registered Apps blade. Go to API permissions to add a permission as normal. When Azure AD displays the range of permissions to select from, click the APIs my organization uses tab, and then type Office 365 Exchange Online into the search box. Azure AD will find the Office 365 Exchange Online API (Figure 1). Note the application identifier shown here. We’ll need this later.
Figure 1: Finding the Office 365 Exchange Online API
Now browse the set of permissions in the Office 365 Exchange Online API and select Exchange.ManageAsApp (Figure 2). Make sure that you’ve selected application permissions and click Add permission. When you return to the app details, consent to the assignment, just like you’d do for a Graph API permission.
Figure 2: Adding the Exchange.ManageAsApp permission
The registered app can now run Exchange Online cmdlets as an administrator. That’s all well and good, but what about a managed identity?
Managed Identities are Different
Unlike registered apps, managed identities show up under the enterprise apps section of the Azure AD admin center. Open enterprise apps and apply a filter to find managed identities (Figure 3).
Figure 3: Selecting managed identities in the Azure AD admin center
Azure AD lists the Azure automation accounts with managed identities. Select the automation account you want to work with. When you access its permissions, Azure AD tells you that: “The ability to consent to this application is disabled as the app does not require consent. Granting consent only applies to applications requiring permissions to access your resources.” In other words, you can’t assign an API to an automation account, or rather the service principal for the managed identity, through the Azure AD admin center.
Instead, you can do the job with PowerShell using cmdlets from the Microsoft Graph PowerShell SDK. Here’s how:
Note the name of the automation account used with the managed identity. In this example, the account name is “ExoAutomationAccount.”
Connect to the Graph with the AppRoleAssignment.ReadWrite.All permission.
Run the Get-MgServicePrincipal cmdlet to populate a variable with the service principal for the automation account. The filter passed to the cmdlet contains the name of the automation account.
Populate a variable with details of the Office 365 Exchange Online enterprise app. Microsoft installs this app for tenants to allow administrative apps to manage Exchange. The app id for the Office 365 Exchange Online app is always 00000002-0000-0ff1-ce00-000000000000.
Find the Manage Exchange As Application role in the set held by the Exchange Online application. This role holds the Exchange.ManageAsApp permission, so any app holding the role can use the permission.
Create the parameters to assign the role to the managed identity.
Use the New-MgServicePrincipalRoleAssignment cmdlet to assign the role.
The new role assignment is effective immediately. If you make a mistake, you can remove the assignment with the Remove-MgServicePrincipalAppRoleAssignment cmdlet. Here’s how:
The final step is to make sure that Exchange Online recognizes the automation account which hosts the managed identity as an Exchange administrator. This is done by assigning the Exchange Administrator role to the automation account’s app in the Azure AD admin center. Figure 4 shows how to add the assignment of the Exchange administrator role to the app owned by an automation account.
Figure 4: Making sure that the Managed Identity can act as an Exchange administrator
If you don’t assign the Exchange administrator role to the automation account’s app, you’ll see an error telling you that the role assigned to the app isn’t supported in this scenario when you execute the runbook. For example:
“The role assigned to application 415e4ba8-635f-4689-b069-22dea1fcfdb3 isn’t supported in this scenario“
Assignment a Small Pain
Perhaps Microsoft under-estimated the continuing need to assign the Exchange.ManageAsApp permission to apps when they made their November 2020 announcement. Although it’s a pain to have to go to PowerShell to assign the permission, it’s something that only needs to happen once, so it’s not too bad. I have other more serious things to moan about inside Microsoft 365.
Learn more about how the Microsoft 365 ecosystem really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.
10 Replies to “Making Sure Apps Can Run Exchange Online Management Cmdlets”
I tried what you subscribed here and I was able to manage to get the admin consent in plave but when I tried the simple runbook to connect and askfor a mailbox I got this error message: The role assigned to application isn’t supported in this scenario. Please check online documentation for assigning correct Directory Roles to Azure AD Application for EXO App-Only Authentication
Connect-ExchangeOnline -ManagedIdentity -Organization “xxxxx.onmicrosoft.com”
# Get the Mailbox
$Mailboxes = Get-Mailbox -Identity “jakke@xxxx.com”
# Output the Results for the Mailbox
Write-Output $Mailboxes
Loading...
I ran this script successfully (altered for my tenant) by changing Get-Mailbox (the old Remote PowerShell cmdlet) to Get-ExoMailbox (the REST-based version).
Loading...
I Added the managed account in the Exchange administrator group and now it seems to be working
Loading...
I am able to get user mailbox information (get-mailbox -identity user@domain.com) in Azure Automation but when I tried to enable online archive I get
“|Microsoft.Exchange.Data.Directory.InsufficientPermissionsException|Source server:CO3PR22MB3373.namprd22.prod.outlook.com doesn’t have write permission to target DC:VI1PR07A04DC004.EURPR07A004.PROD.OUTLOOK.COM. Usually it indicates that target forest isn’t an account partition of source forest. Additional information: Insufficient access rights to perform the operation.
Active directory response: 00002098: SecErr: DSID-031514A0, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0”
Command used to enable online archive: Enable-Mailbox -Identity user@domain.com -Archive
The managed identity have “Manage Exchange As Application” permission and Exchange admin role. I don’t what other role it needs or limitation with system managed identity using Exchange module 3.0
I created a new automation, runbook but still have the same problem. May I know what runbook runtime version you used?
For me, I am using the following:
-System managed identity
-Runbook version 5.1
-All module are version 5.1
-Used the said role and permission you stated in your document ( Manage Exchange As Application and Exchange admin role)
Loading...
That’s exactly how I have it set up. Version 5.1.
Are you able to use the runbook to set a mailbox property? For example, Set-Mailbox -Id Mbx -CustomAttribute1 “Test”
|Microsoft.Exchange.Data.Directory.InsufficientPermissionsException|Source server:PH0PR13MB5949.namprd13.prod.outlook.com doesn’t have write permission to target DC:AM0PR07A04DC006.EURPR07A004.PROD.OUTLOOK.COM. Usually it indicates that target forest isn’t an account partition of source forest. Additional information: Insufficient access rights to perform the operation.
Active directory response: 00002098: SecErr: DSID-031514A0, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0
>Doing Get-Mailbox -Id Mbx | FL CustomAttribute*. Is without a problem.
>I granted the managed identity global admin role but still the same. Tested on a brand new mailbox.
>I will keep investigating this. Hopefully I have answer and will share once I find it.
{"id":null,"mode":"button","open_style":"in_modal","currency_code":"EUR","currency_symbol":"\u20ac","currency_type":"decimal","blank_flag_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":100,"top_media_type":"featured_image","featured_image_url":"https:\/\/office365itpros.com\/wp-content\/uploads\/2022\/11\/cover-141x200.jpg","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":true,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Virtual Tip Jar","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"Office 365 for IT Pros","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"Office 365 for IT Pros","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for supporting the work of Office 365 for IT Pros!","payment_confirmation_title":"Office 365 for IT Pros","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":null,"terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}
I tried what you subscribed here and I was able to manage to get the admin consent in plave but when I tried the simple runbook to connect and askfor a mailbox I got this error message: The role assigned to application isn’t supported in this scenario. Please check online documentation for assigning correct Directory Roles to Azure AD Application for EXO App-Only Authentication
Can you paste the code you’re trying to run here?
Connect-ExchangeOnline -ManagedIdentity -Organization “xxxxx.onmicrosoft.com”
# Get the Mailbox
$Mailboxes = Get-Mailbox -Identity “jakke@xxxx.com”
# Output the Results for the Mailbox
Write-Output $Mailboxes
I ran this script successfully (altered for my tenant) by changing Get-Mailbox (the old Remote PowerShell cmdlet) to Get-ExoMailbox (the REST-based version).
I Added the managed account in the Exchange administrator group and now it seems to be working
I am able to get user mailbox information (get-mailbox -identity user@domain.com) in Azure Automation but when I tried to enable online archive I get
“|Microsoft.Exchange.Data.Directory.InsufficientPermissionsException|Source server:CO3PR22MB3373.namprd22.prod.outlook.com doesn’t have write permission to target DC:VI1PR07A04DC004.EURPR07A004.PROD.OUTLOOK.COM. Usually it indicates that target forest isn’t an account partition of source forest. Additional information: Insufficient access rights to perform the operation.
Active directory response: 00002098: SecErr: DSID-031514A0, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0”
Command used to enable online archive: Enable-Mailbox -Identity user@domain.com -Archive
The managed identity have “Manage Exchange As Application” permission and Exchange admin role. I don’t what other role it needs or limitation with system managed identity using Exchange module 3.0
Full command:
Connect-ExchangeOnline -ManagedIdentity -Organization OrganisationName.onmicrosoft.com
Connect-AzAccount -Identity
Connect-MgGraph -AccessToken ((Get-AzAccessToken -ResourceTypeName MSGraph).token)
Enable-Mailbox -Identity user@domain.com -Archive
This runbook worked for me:
Connect-AzAccount -Identity
$AccessToken = Get-AzAccessToken -ResourceUrl “https://graph.microsoft.com”
# Connect to Exchange Online
Connect-ExchangeOnline -ManagedIdentity -Organization redmondassociates.onmicrosoft.com
Enable-Mailbox -Identity Jess.Cooper@office365itpros.com -Archive
get-exomailbox jess.cooper@office365itpros.com -PropertySets all | fl *arch*
IsExcludedFromServingHierarchy : False
IsHierarchyReady : True
IsHierarchySyncEnabled : True
ArchiveDatabase : EURPR04DG586-db514
ArchiveGuid : 7a906f36-8e00-4fc3-a588-cb0e289342b7
ArchiveName : {In-Place Archive -Jess Cooper (Information Technology)}
JournalArchiveAddress :
ArchiveQuota : 100 GB (107,374,182,400 bytes)
ArchiveWarningQuota : 90 GB (96,636,764,160 bytes)
ArchiveDomain :
ArchiveStatus : Active
ArchiveState : Local
AutoExpandingArchiveEnabled : False
DisabledArchiveDatabase :
DisabledArchiveGuid : 00000000-0000-0000-0000-000000000000
ArchiveRelease :
I created a new automation, runbook but still have the same problem. May I know what runbook runtime version you used?
For me, I am using the following:
-System managed identity
-Runbook version 5.1
-All module are version 5.1
-Used the said role and permission you stated in your document ( Manage Exchange As Application and Exchange admin role)
That’s exactly how I have it set up. Version 5.1.
Are you able to use the runbook to set a mailbox property? For example, Set-Mailbox -Id Mbx -CustomAttribute1 “Test”
>Doing Set-Mailbox -Id Mbx -CustomAttribute1 “Test”
I still get the same error:
|Microsoft.Exchange.Data.Directory.InsufficientPermissionsException|Source server:PH0PR13MB5949.namprd13.prod.outlook.com doesn’t have write permission to target DC:AM0PR07A04DC006.EURPR07A004.PROD.OUTLOOK.COM. Usually it indicates that target forest isn’t an account partition of source forest. Additional information: Insufficient access rights to perform the operation.
Active directory response: 00002098: SecErr: DSID-031514A0, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0
>Doing Get-Mailbox -Id Mbx | FL CustomAttribute*. Is without a problem.
>I granted the managed identity global admin role but still the same. Tested on a brand new mailbox.
>I will keep investigating this. Hopefully I have answer and will share once I find it.