{"id":62953,"date":"2025-12-01T07:00:00","date_gmt":"2025-12-01T12:00:00","guid":{"rendered":"https:\/\/practical365.com\/?p=62953"},"modified":"2025-11-26T13:03:01","modified_gmt":"2025-11-26T18:03:01","slug":"exchange-admin-api","status":"publish","type":"post","link":"https:\/\/practical365.com\/exchange-admin-api\/","title":{"rendered":"How to Use the Exchange Admin API"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 eztoc-toggle-hide-by-default' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/practical365.com\/exchange-admin-api\/#Limited_API_Designed_to_Patch_Hole_in_EWS_Migration_Story\" >Limited API Designed to Patch Hole in EWS Migration Story<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/practical365.com\/exchange-admin-api\/#Selecting_an_App_to_Interact_with_the_Exchange_Admin_API\" >Selecting an App to Interact with the Exchange Admin API<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/practical365.com\/exchange-admin-api\/#Assign_Exchange_Online_RBAC_Roles_to_the_App\" >Assign Exchange Online RBAC Roles to the App<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/practical365.com\/exchange-admin-api\/#Securing_an_Access_Token\" >Securing an Access Token<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/practical365.com\/exchange-admin-api\/#Accessing_the_Exchange_Online_Organization_Configuration\" >Accessing the Exchange Online Organization Configuration<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/practical365.com\/exchange-admin-api\/#Fetching_Mailboxes\" >Fetching Mailboxes<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/practical365.com\/exchange-admin-api\/#A_Small_but_Important_Part_in_the_EWS_Migration_Story\" >A Small but Important Part in the EWS Migration Story<\/a><\/li><\/ul><\/nav><\/div>\n<div id=\"bsf_rt_marker\"><\/div>\n<h2 class=\"wp-block-heading\" id=\"h-limited-api-designed-to-patch-hole-in-ews-migration-story\"><span class=\"ez-toc-section\" id=\"Limited_API_Designed_to_Patch_Hole_in_EWS_Migration_Story\"><\/span>Limited API Designed to Patch Hole in EWS Migration Story<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Microsoft launched the <a href=\"https:\/\/office365itpros.com\/2025\/11\/18\/exchange-admin-api-preview\/\" target=\"_blank\" rel=\"noreferrer noopener\">Exchange Admin API<\/a> on November 17. The API is a plaster to cover up some of the obvious gaps in functionality that exist between what developers can do in Exchange Web Services (EWS) and what can be done using Graph APIs. Microsoft is due to retire EWS from Exchange Online in October 2026, so there\u2019s not a lot of time available for developers to migrate their EWS code to a supported platform. The Exchange Admin API exists to assist in that effort.<\/p>\n\n\n\n<p>The intention is that apps like email clients that are migrating their code base from EWS will use the Exchange Admin API to migrate code by using a wrapper to execute Exchange PowerShell cmdlets to recreate functionality that is often used in EWS. The cmdlets return data that the apps can use in their processing.<\/p>\n\n\n\n<p>As we\u2019ll discover, the Exchange Admin API is very limited and things that you might assume are possible cannot be achieved in many cases. This is by design. Microsoft did not set out to build a new REST-based API for general-purpose Exchange Online administration. Instead, the Exchange Admin API offers just enough support to allow developers to migrate apps off EWS in the limited circumstances when a Graph API is unavailable.<\/p>\n\n\n\n<p>In most cases, the right choice to build administrative automation for Exchange Online is PowerShell using a mixture of cmdlets from the Exchange Online module and the Microsoft Graph PowerShell SDK. I can\u2019t think of a reason why anyone writing a PowerShell script will consider using the Exchange Admin API for a very simple reason: the script can run the cmdlets supported by the API natively. Even better, running the cmdlets natively is more functional and powerful than running cmdlets through the Exchange Admin API.<\/p>\n\n\n\n<p>However, it\u2019s interesting to understand how things work, and if you\u2019ve worked with the Microsoft Graph through PowerShell, most of what needs to be done will be familiar territory. Let\u2019s see how to interact with Exchange through the Exchange Admin API.<\/p>\n\n\n\n<div class=\"q-blockads-inside-content q-blockads-entity-placement\" id=\"q-blockads-3517261110\"><div id=\"q-blockads-2762804676\"><p><a href=\"https:\/\/www.quest.com\/P365_On_Demand_Migration\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-62892\" src=\"https:\/\/practical365.com\/wp-content\/uploads\/2024\/09\/1901-10-20-2025-Redone-300x31.jpg\" alt=\"\" width=\"861\" height=\"89\" srcset=\"https:\/\/practical365.com\/wp-content\/uploads\/2024\/09\/1901-10-20-2025-Redone-300x31.jpg 300w, https:\/\/practical365.com\/wp-content\/uploads\/2024\/09\/1901-10-20-2025-Redone-768x80.jpg 768w, https:\/\/practical365.com\/wp-content\/uploads\/2024\/09\/1901-10-20-2025-Redone.jpg 860w\" sizes=\"auto, (max-width: 861px) 100vw, 861px\" \/><\/a><\/p>\n<\/div><\/div><h2 class=\"wp-block-heading\" id=\"h-selecting-an-app-to-interact-with-the-exchange-admin-api\"><span class=\"ez-toc-section\" id=\"Selecting_an_App_to_Interact_with_the_Exchange_Admin_API\"><\/span>Selecting an App to Interact with the Exchange Admin API<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Apps and service principals provide the foundation for app-centric authorization and authentication in Entra ID. Developers who use the Exchange Admin API will have their own app. To mimic the situation in PowerShell, the first step is to create a registered app (or reuse an existing app). A new app can be created through the Entra admin center or by running the <em>New-MgApplication<\/em> cmdlet. The app serves as the identity to interact with Exchange Online via the API. As we\u2019ll see, the app\u2019s service principal must be assigned an Exchange Online permission and one or more Exchange Online roles to allow the app to run cmdlets via the API.<\/p>\n\n\n\n<p>After you know which app to use, grant consent to the app to use the Exchange.ManageAsAppV2 application permission from the Office 365 Exchange Online app (Figure 1). The process to assign the permission is the same as used to assign consent for an app to use a Graph permission. What\u2019s different is the source resource, which is Office 365 Exchange Online.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"460\" src=\"https:\/\/practical365.com\/wp-content\/uploads\/2025\/11\/Exchange-Admin-API-App-1024x460.jpg\" alt=\"Details of an Entra ID registered app used with the Exchange Admin API.\" class=\"wp-image-62954\" srcset=\"https:\/\/practical365.com\/wp-content\/uploads\/2025\/11\/Exchange-Admin-API-App-1024x460.jpg 1024w, https:\/\/practical365.com\/wp-content\/uploads\/2025\/11\/Exchange-Admin-API-App-300x135.jpg 300w, https:\/\/practical365.com\/wp-content\/uploads\/2025\/11\/Exchange-Admin-API-App-768x345.jpg 768w, https:\/\/practical365.com\/wp-content\/uploads\/2025\/11\/Exchange-Admin-API-App.jpg 1075w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Figure 1: Details of an Entra ID registered app used with the Exchange Admin API<\/figcaption><\/figure>\n<\/div>\n\n\n<p>In addition, load an X.509 certificate (a self-signed certificate is fine) into the app. We\u2019ll use the certificate to authenticate with Entra ID and obtain an access token to allow PowerShell to use the Exchange Admin API.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Assign_Exchange_Online_RBAC_Roles_to_the_App\"><\/span>Assign Exchange Online RBAC Roles to the App<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>The next step is to make sure that the app has the correct Exchange Online administrative roles to allow the app to function as if it was a human administrator. To begin, run the <em>Connect-MgGraph<\/em> cmdlet to create an interactive Graph session and fetch details of the app\u2019s service principal:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Connect-MgGraph -scopes Application.ReadWrite.All -NoWelcome\n$ExoAdminSP = Get-MgServicePrincipal -Filter \"displayname eq 'ExoAdminAPI'\"\n$ExoAdminSP\n\nDisplayName Id                                   AppId                                SignInAudience ServicePrincipalType\n----------- --                                   -----                                -------------- --------------------\nExoAdminAPI 1c0cf40b-2c6c-4030-a0c3-70284bedf5b7 0559c362-c681-4108-86ff-d7c006643a9d AzureADMyOrg   Application\n<\/pre>\n\n\n\n<p>Entra ID service principals don\u2019t exist in Exchange Online. To create a link between Entra ID and Exchange Online, connect to Exchange Online to create an Exchange service principal for the Entra ID service principal. Here are the commands:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Connect-ExchangeOnline -ShowBanner:$False -ErrorAction Stop\n\nNew-ServicePrincipal -Appid $ExoAdminSP.AppId -ServiceId $ExoAdminSP.Id -DisplayName 'Exo Admin API App'\n\nDisplayName                              ObjectId                                                             AppId\n-----------                              --------                                                             -----\nExo Admin API App                        1c0cf40b-2c6c-4030-a0c3-70284bedf5b7                                 0559c362-c681-4108-86ff-d7c006643a9d\n<\/pre>\n\n\n\n<p>Linking the two types of service principals is the same mechanism as used in <a href=\"https:\/\/practical365.com\/rbac-for-applications\/\" target=\"_blank\" rel=\"noreferrer noopener\">RBAC for Applications<\/a> to control app access to mailboxes. We\u2019ll use the Exchange service principal to assign the necessary Exchange RBAC roles. To make the next step easier, populate a variable with the details of the new Exchange service principal:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ExoAdminSPExo = Get-ServicePrincipal -Identity 'Exo Admin API App'<\/pre>\n\n\n\n<p>Now use the Exchange service principal to add the app to the <em>View-Only Organization Management<\/em> and <em>Recipient Management<\/em> role groups. The first role group allows access to the organization and domains endpoints. The second role group takes care of the other four endpoints:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Update-RoleGroupMember -Identity \"View-Only Organization Management\" -Members @{Add=\"$ExoAdminSPEXO\"}\n\nConfirm\nAre you sure you want to perform this action?\nUpdating the role group Identity:\"View-Only Organization Management\" with the member list \"Add=1c0cf40b-2c6c-4030-a0c3-70284bedf5b7;\".\n[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is \"Y\"): y\n\nUpdate-RoleGroupMember -Identity \"Recipient Management\" -Members @{Add=\"$ExoAdminSPEXO\"}\n\nConfirm\nAre you sure you want to perform this action?\nUpdating the role group Identity:\"Recipient Management\" with the member list \"Add=1c0cf40b-2c6c-4030-a0c3-70284bedf5b7;\".\n[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is \"Y\"): y\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Securing_an_Access_Token\"><\/span>Securing an Access Token<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>With the app correctly permissioned, we proceed to authentication. Details of how to authenticate the app with Exchange Online is <a href=\"https:\/\/learn.microsoft.com\/en-gb\/exchange\/reference\/admin-api-authentication?WT.mc_id=M365-MVP-9501\" target=\"_blank\" rel=\"noreferrer noopener\">covered in this documentation<\/a>. The basic idea is to obtain an access token from Entra ID that the app can use to prove its right to run the Exchange Admin API.<\/p>\n\n\n\n<p>The <a href=\"https:\/\/www.powershellgallery.com\/packages\/PSMSALNet\/0.1.3\" target=\"_blank\" rel=\"noreferrer noopener\">PSMSALNet module<\/a> is a convenient way to obtain an <a href=\"https:\/\/office365itpros.com\/2022\/02\/17\/understanding-entra-id-access-token\/\" target=\"_blank\" rel=\"noreferrer noopener\">access token from Entra ID<\/a> (be sure to <a href=\"https:\/\/github.com\/SCOMnewbie\/PSMSALNet\" target=\"_blank\" rel=\"noreferrer noopener\">read the module documentation<\/a>). Several parameter values are required, including the application identifier of the Office 365 Exchange Online service principal, which we get with:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Get-MgServicePrincipal -filter \"displayName eq 'Office 365 Exchange Online'\" | Format-Table DisplayName, AppId\n\nDisplayName                AppId\n-----------                -----\nOffice 365 Exchange Online 00000002-0000-0ff1-ce00-000000000000\n<\/pre>\n\n\n\n<p>The other parameters are the tenant identifier, the certificate that\u2019s been uploaded to the app, and the app identifier. In this example, I use the thumbprint of the certificate to fetch its details. The parameters are placed into a hash table and used by the <em>Get-EntraToken<\/em> cmdlet to obtain an access token.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$Thumbprint = '0CF6CE3F3548FD73E7AC8CF20226ED447E125C71'\n$AppId =  (Get-MgServicePrincipal -filter \"displayName eq 'ExoAdminAPI'\").AppId\n$TenantId = (Get-MgOrganization).Id\n$Certificate = Get-Item (\"Cert:\\CurrentUser\\My\\\"+$Thumbprint)\n$Parameters = @{}\n$Parameters.Add(\"TenantId\",$TenantId)\n$Parameters.Add(\"ClientId\",$AppId)\n$Parameters.Add(\"CustomResource\",'00000002-0000-0ff1-ce00-000000000000')\n$Parameters.Add(\"ClientCertificate\", $Certificate)\n$Parameters.Add(\"Resource\", \"Custom\")\n\n$Token = Get-EntraToken -ClientCredentialFlowWithCertificate @Parameters\n<\/pre>\n\n\n\n<p>The PSMSALNet module suffers from an <a href=\"https:\/\/office365itpros.com\/2025\/09\/24\/assembly-clash-microsoft-365-ps\/\" target=\"_blank\" rel=\"noreferrer noopener\">assembly clash<\/a> with the Exchange Online module. To avoid the issue, run <em>Connect-MgGraph<\/em> first in a new PowerShell session, and then run <em>Get-EntraToken<\/em>. You\u2019ll know if the problem happens if you see something like this:<\/p>\n\n\n\n<p><em>Get-EntraToken: The &#8216;Get-EntraToken&#8217; command was found in the module &#8216;PSMSALNet&#8217;, but the module could not be loaded due to the following error: [Could not load file or assembly &#8216;Microsoft.Identity.Client, Version=4.66.1.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae&#8217;. Assembly with same name is already loaded]<\/em><\/p>\n\n\n\n<div class=\"q-blockads-content q-blockads-entity-placement\" id=\"q-blockads-3570535883\"><div id=\"q-blockads-4084791134\"><p><a href=\"https:\/\/www.quest.com\/Security_Guardian_P365\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-62893\" src=\"https:\/\/practical365.com\/wp-content\/uploads\/2024\/04\/1902-10-20-2025-Redone-300x31.jpg\" alt=\"\" width=\"861\" height=\"89\" srcset=\"https:\/\/practical365.com\/wp-content\/uploads\/2024\/04\/1902-10-20-2025-Redone-300x31.jpg 300w, https:\/\/practical365.com\/wp-content\/uploads\/2024\/04\/1902-10-20-2025-Redone-768x80.jpg 768w, https:\/\/practical365.com\/wp-content\/uploads\/2024\/04\/1902-10-20-2025-Redone.jpg 860w\" sizes=\"auto, (max-width: 861px) 100vw, 861px\" \/><\/a><\/p>\n<\/div><\/div><h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Accessing_the_Exchange_Online_Organization_Configuration\"><\/span>Accessing the Exchange Online Organization Configuration<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>With an access token, we can use the Exchange Admin API. This example shows how to run the <em>Get-OrganizationConfig<\/em> cmdlet to retrieve details of the tenant configuration. The basics of the API are revealed. Requests are posted to the target endpoint to retrieve information. Each request contains a JSON-format body with details of the information the app wants from Exchange. It\u2019s up to the app to do whatever it wants with the information that it receives from Exchange.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$Headers = @{\"Authorization\" = \"Bearer \"+ $Token.AccessToken}\n$ContentType = \"application\/json\"\n$URI = (\"https:\/\/outlook.office365.com\/adminapi\/v2.0\/{0}\/OrganizationConfig\" -f $TenantId)\n\n$Body = @\"\n{\n    \"CmdletInput\": {\n        \"CmdletName\": \"Get-OrganizationConfig\"\n    }\n}\n\"@\n\n$ExoResult = (Invoke-RestMethod -URI $Uri -Headers $Headers -Method \"POST\" -Body $Body -ContentType $ContentType).Value\nIf ($ExoResult) {\n   Write-Host (\u201cThe tenant identity is {0} and its SharePoint root is {1}\u201d -f $ExoResult.Identity, $ExoResult.SharePointURL)\n}\n\nThe tenant identity is Office365itpros.onmicrosoft.com and its SharePoint root is https:\/\/office365itpros.sharepoint.com\/\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Fetching_Mailboxes\"><\/span>Fetching Mailboxes<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>For recipient management, an \u201canchor mailbox\u201d is required to tell Exchange Online which server should handle the request. The mailbox endpoint is quite limited and only supports a couple of operations for the <em>Get-Mailbox<\/em> and <em>Set-Mailbox<\/em> cmdlets (why <em>Get-ExoMailbox<\/em> is not used is unknown).<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$XAnchorMailbox = \"Lotte.Vetler@office365itpros.com\"\n$Headers = @{\"Authorization\" = \"Bearer \"+ $Token.AccessToken;\"X-AnchorMailbox\" = \"UPN:$XAnchorMailbox\"}\n$ContentType = \"application\/json\"\n$URI = (\"https:\/\/outlook.office365.com\/adminapi\/v2.0\/{0}\/Mailbox\" -f $TenantId)\n$Body = @\"\n{\n  \"CmdletInput\": {\n    \"CmdletName\": \"Get-Mailbox\",\n    \"Parameters\": {       \n      \"ResultSize\": \"Unlimited\"             \n    }\n  }\n}\n\"@\n[array]$Mailboxes = (Invoke-RestMethod -URI $Uri -Headers $Headers -Method \"POST\" -Body $Body -ContentType $ContentType).Value\nIf ($Mailboxes) {\n  Write-Host (\"{0} mailboxes fetched\u2026\" -f $Mailboxes.count)\n}\n<\/pre>\n\n\n\n<p>Before you get too excited about this endpoint, read <a href=\"https:\/\/learn.microsoft.com\/en-gb\/exchange\/reference\/admin-api-endpoints-mailbox?WT.mc_id=M365-MVP-9501\">the documentation<\/a>. The lack of functionality is immediately available, but the biggest issue is no support for server-side filtering. I can\u2019t understand why Microsoft left filtering out, especially when the documentation covers the topic of <a href=\"https:\/\/learn.microsoft.com\/en-gb\/exchange\/reference\/admin-api-get-started?WT.mc_id=M365-MVP-9501#pagination\">pagination and property selection<\/a> when retrieving multiple items.<\/p>\n\n\n\n<p>For example, the code above fetches all mailboxes. The result could be 50 mailboxes, but it might be 50,000. Not being able to use server-side filtering means that, to find the set of shared mailboxes, an app must ask for all mailboxes and then apply a client-side filter to extract the relevant set. This is pure folly and is a great example of code that works splendidly in a test environment that\u2019s utterly useless in production. I guess Microsoft never tried to use the mailbox endpoint in their own environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-a-small-but-important-part-in-the-ews-migration-story\"><span class=\"ez-toc-section\" id=\"A_Small_but_Important_Part_in_the_EWS_Migration_Story\"><\/span>A Small but Important Part in the EWS Migration Story<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>There\u2019s no point in showing how to use the other endpoints supported by the Exchange Admin API. Everything works in the same limited way. If you\u2019re looking for more details, MVP Vasil Michev has an interesting perspective on <a href=\"https:\/\/michev.info\/blog\/post\/5822\/all-you-need-to-know-about-exchange-online-admin-api-or-how-to-run-cmdlets-without-powershell\" target=\"_blank\" rel=\"noreferrer noopener\">how the API functions<\/a>.<\/p>\n\n\n\n<p>Microsoft documentation is available online for those who need to upgrade their code to move away from EWS before the hatchet descends in ten months\u2019 time. In that light, the Exchange Admin API is a useful tool to help finish code migrations. Anyone else who might think that an Exchange Admin API is the way to automate Exchange operations will be sadly disappointed.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On November 17, Microsoft announced the Exchange Admin API, a REST-based method of interacting with Exchange Online administrative functions. Having a new API sounds exciting, but in reality the Exchange Admin API is a limited tool to help Exchange Web Services (EWS) developers migrate their apps before Microsoft retires EWS in October 2026. That being said, here&#8217;s how the API works.<\/p>\n","protected":false},"author":84,"featured_media":54388,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[26],"tags":[11518,739,11517,480,238],"class_list":["post-62953","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-exchange-online","tag-app-migration","tag-ews","tag-exchange-admin-api","tag-exchange-web-services","tag-powershell","entry","has-media"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.2 (Yoast SEO v27.5) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How to Use the Exchange Admin API | Practical365<\/title>\n<meta name=\"description\" content=\"On November 17, Microsoft announced the Exchange Admin API, a REST-based method of interacting with Exchange Online administrative functions. Having a new API sounds exciting, but in reality the Exchange Admin API is a limited tool to help Exchange Web Services (EWS) developers migrate their apps before Microsoft retires EWS in October 2026. That being said, here&#039;s how the API works.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/practical365.com\/exchange-admin-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Use the Exchange Admin API\" \/>\n<meta property=\"og:description\" content=\"On November 17, Microsoft announced the Exchange Admin API, a REST-based method of interacting with Exchange Online administrative functions. Having a new API sounds exciting, but in reality the Exchange Admin API is a limited tool to help Exchange Web Services (EWS) developers migrate their apps before Microsoft retires EWS in October 2026. That being said, here&#039;s how the API works.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/practical365.com\/exchange-admin-api\/\" \/>\n<meta property=\"og:site_name\" content=\"Practical 365\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Practical365\" \/>\n<meta property=\"article:published_time\" content=\"2025-12-01T12:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/practical365.com\/wp-content\/uploads\/2021\/12\/Microsoft-Loop-news.png\" \/>\n\t<meta property=\"og:image:width\" content=\"734\" \/>\n\t<meta property=\"og:image:height\" content=\"396\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Tony Redmond\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/12Knocksinna\" \/>\n<meta name=\"twitter:site\" content=\"@Practical365\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tony Redmond\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/\"},\"author\":{\"name\":\"Tony Redmond\",\"@id\":\"https:\\\/\\\/practical365.com\\\/#\\\/schema\\\/person\\\/19d7b2f404dd1da1d87586fb07015a19\"},\"headline\":\"How to Use the Exchange Admin API\",\"datePublished\":\"2025-12-01T12:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/\"},\"wordCount\":1417,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/practical365.com\\\/wp-content\\\/uploads\\\/2021\\\/12\\\/Microsoft-Loop-news.png\",\"keywords\":[\"App migration\",\"EWS\",\"Exchange Admin API\",\"Exchange Web Services\",\"PowerShell\"],\"articleSection\":[\"Exchange Online\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/\",\"url\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/\",\"name\":\"How to Use the Exchange Admin API | Practical365\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/practical365.com\\\/wp-content\\\/uploads\\\/2021\\\/12\\\/Microsoft-Loop-news.png\",\"datePublished\":\"2025-12-01T12:00:00+00:00\",\"description\":\"On November 17, Microsoft announced the Exchange Admin API, a REST-based method of interacting with Exchange Online administrative functions. Having a new API sounds exciting, but in reality the Exchange Admin API is a limited tool to help Exchange Web Services (EWS) developers migrate their apps before Microsoft retires EWS in October 2026. That being said, here's how the API works.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/#primaryimage\",\"url\":\"https:\\\/\\\/practical365.com\\\/wp-content\\\/uploads\\\/2021\\\/12\\\/Microsoft-Loop-news.png\",\"contentUrl\":\"https:\\\/\\\/practical365.com\\\/wp-content\\\/uploads\\\/2021\\\/12\\\/Microsoft-Loop-news.png\",\"width\":734,\"height\":396},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/practical365.com\\\/exchange-admin-api\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/practical365.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Exchange Online\",\"item\":\"https:\\\/\\\/practical365.com\\\/exchange-online\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"How to Use the Exchange Admin API\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/practical365.com\\\/#website\",\"url\":\"https:\\\/\\\/practical365.com\\\/\",\"name\":\"Practical 365\",\"description\":\"Practical Office 365 News, Tips, and Tutorials\",\"publisher\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/practical365.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/practical365.com\\\/#organization\",\"name\":\"Practical 365\",\"url\":\"https:\\\/\\\/practical365.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/practical365.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/practical365.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/Logo-P365-stacked.jpg\",\"contentUrl\":\"https:\\\/\\\/practical365.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/Logo-P365-stacked.jpg\",\"width\":1176,\"height\":696,\"caption\":\"Practical 365\"},\"image\":{\"@id\":\"https:\\\/\\\/practical365.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/Practical365\",\"https:\\\/\\\/x.com\\\/Practical365\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/practical365-com\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/practical365.com\\\/#\\\/schema\\\/person\\\/19d7b2f404dd1da1d87586fb07015a19\",\"name\":\"Tony Redmond\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/practical365.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/cropped-TonyRedmondHeadShot2016-1200-96x96.jpg\",\"url\":\"https:\\\/\\\/practical365.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/cropped-TonyRedmondHeadShot2016-1200-96x96.jpg\",\"contentUrl\":\"https:\\\/\\\/practical365.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/cropped-TonyRedmondHeadShot2016-1200-96x96.jpg\",\"caption\":\"Tony Redmond\"},\"description\":\"Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.\",\"sameAs\":[\"https:\\\/\\\/office365itpros.com\",\"https:\\\/\\\/x.com\\\/https:\\\/\\\/twitter.com\\\/12Knocksinna\"],\"url\":\"https:\\\/\\\/practical365.com\\\/author\\\/tony-redmondredmondassociates-org\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Use the Exchange Admin API | Practical365","description":"On November 17, Microsoft announced the Exchange Admin API, a REST-based method of interacting with Exchange Online administrative functions. Having a new API sounds exciting, but in reality the Exchange Admin API is a limited tool to help Exchange Web Services (EWS) developers migrate their apps before Microsoft retires EWS in October 2026. That being said, here's how the API works.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/practical365.com\/exchange-admin-api\/","og_locale":"en_US","og_type":"article","og_title":"How to Use the Exchange Admin API","og_description":"On November 17, Microsoft announced the Exchange Admin API, a REST-based method of interacting with Exchange Online administrative functions. Having a new API sounds exciting, but in reality the Exchange Admin API is a limited tool to help Exchange Web Services (EWS) developers migrate their apps before Microsoft retires EWS in October 2026. That being said, here's how the API works.","og_url":"https:\/\/practical365.com\/exchange-admin-api\/","og_site_name":"Practical 365","article_publisher":"https:\/\/www.facebook.com\/Practical365","article_published_time":"2025-12-01T12:00:00+00:00","og_image":[{"width":734,"height":396,"url":"https:\/\/practical365.com\/wp-content\/uploads\/2021\/12\/Microsoft-Loop-news.png","type":"image\/png"}],"author":"Tony Redmond","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/12Knocksinna","twitter_site":"@Practical365","twitter_misc":{"Written by":"Tony Redmond","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/practical365.com\/exchange-admin-api\/#article","isPartOf":{"@id":"https:\/\/practical365.com\/exchange-admin-api\/"},"author":{"name":"Tony Redmond","@id":"https:\/\/practical365.com\/#\/schema\/person\/19d7b2f404dd1da1d87586fb07015a19"},"headline":"How to Use the Exchange Admin API","datePublished":"2025-12-01T12:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/practical365.com\/exchange-admin-api\/"},"wordCount":1417,"commentCount":0,"publisher":{"@id":"https:\/\/practical365.com\/#organization"},"image":{"@id":"https:\/\/practical365.com\/exchange-admin-api\/#primaryimage"},"thumbnailUrl":"https:\/\/practical365.com\/wp-content\/uploads\/2021\/12\/Microsoft-Loop-news.png","keywords":["App migration","EWS","Exchange Admin API","Exchange Web Services","PowerShell"],"articleSection":["Exchange Online"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/practical365.com\/exchange-admin-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/practical365.com\/exchange-admin-api\/","url":"https:\/\/practical365.com\/exchange-admin-api\/","name":"How to Use the Exchange Admin API | Practical365","isPartOf":{"@id":"https:\/\/practical365.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/practical365.com\/exchange-admin-api\/#primaryimage"},"image":{"@id":"https:\/\/practical365.com\/exchange-admin-api\/#primaryimage"},"thumbnailUrl":"https:\/\/practical365.com\/wp-content\/uploads\/2021\/12\/Microsoft-Loop-news.png","datePublished":"2025-12-01T12:00:00+00:00","description":"On November 17, Microsoft announced the Exchange Admin API, a REST-based method of interacting with Exchange Online administrative functions. Having a new API sounds exciting, but in reality the Exchange Admin API is a limited tool to help Exchange Web Services (EWS) developers migrate their apps before Microsoft retires EWS in October 2026. That being said, here's how the API works.","breadcrumb":{"@id":"https:\/\/practical365.com\/exchange-admin-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/practical365.com\/exchange-admin-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/practical365.com\/exchange-admin-api\/#primaryimage","url":"https:\/\/practical365.com\/wp-content\/uploads\/2021\/12\/Microsoft-Loop-news.png","contentUrl":"https:\/\/practical365.com\/wp-content\/uploads\/2021\/12\/Microsoft-Loop-news.png","width":734,"height":396},{"@type":"BreadcrumbList","@id":"https:\/\/practical365.com\/exchange-admin-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/practical365.com\/"},{"@type":"ListItem","position":2,"name":"Exchange Online","item":"https:\/\/practical365.com\/exchange-online\/"},{"@type":"ListItem","position":3,"name":"How to Use the Exchange Admin API"}]},{"@type":"WebSite","@id":"https:\/\/practical365.com\/#website","url":"https:\/\/practical365.com\/","name":"Practical 365","description":"Practical Office 365 News, Tips, and Tutorials","publisher":{"@id":"https:\/\/practical365.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/practical365.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/practical365.com\/#organization","name":"Practical 365","url":"https:\/\/practical365.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/practical365.com\/#\/schema\/logo\/image\/","url":"https:\/\/practical365.com\/wp-content\/uploads\/2022\/06\/Logo-P365-stacked.jpg","contentUrl":"https:\/\/practical365.com\/wp-content\/uploads\/2022\/06\/Logo-P365-stacked.jpg","width":1176,"height":696,"caption":"Practical 365"},"image":{"@id":"https:\/\/practical365.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Practical365","https:\/\/x.com\/Practical365","https:\/\/www.linkedin.com\/company\/practical365-com"]},{"@type":"Person","@id":"https:\/\/practical365.com\/#\/schema\/person\/19d7b2f404dd1da1d87586fb07015a19","name":"Tony Redmond","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/practical365.com\/wp-content\/uploads\/2022\/06\/cropped-TonyRedmondHeadShot2016-1200-96x96.jpg","url":"https:\/\/practical365.com\/wp-content\/uploads\/2022\/06\/cropped-TonyRedmondHeadShot2016-1200-96x96.jpg","contentUrl":"https:\/\/practical365.com\/wp-content\/uploads\/2022\/06\/cropped-TonyRedmondHeadShot2016-1200-96x96.jpg","caption":"Tony Redmond"},"description":"Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.","sameAs":["https:\/\/office365itpros.com","https:\/\/x.com\/https:\/\/twitter.com\/12Knocksinna"],"url":"https:\/\/practical365.com\/author\/tony-redmondredmondassociates-org\/"}]}},"_links":{"self":[{"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/posts\/62953","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/users\/84"}],"replies":[{"embeddable":true,"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/comments?post=62953"}],"version-history":[{"count":0,"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/posts\/62953\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/media\/54388"}],"wp:attachment":[{"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/media?parent=62953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/categories?post=62953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/practical365.com\/wp-json\/wp\/v2\/tags?post=62953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}