Anyone that’s running admin tasks in Exchange Online is probably aware that a new, “V2” module has been released, featuring some faster and much more reliable cmdlets (in case you aren’t, watch this Ignite session). Those are backed by REST API endpoints, similar to the Graph API that covers most other workloads in Office 365. While Exchange Online is yet to support the Graph (or should it be the other way around?), the new REST endpoints can be exploited in a similar manner, as long as you know what you’re doing. Let’s see how.
First things first, you need to authenticate and in order to do that you need a token. To obtain a token, you must specify few bits of information, such as the clientID and resource, all of which you can obtain by running a Fiddler trace or in some cases by crawling the sign-in logs. Once you have all the details, you can either use the ADAL/MSAL binaries or directly issue a web request to obtain the token. I find it easier to use the former approach, so here’s a code snippet that loads the corresponding binaries and calls the AcquireTokenAsync method:
Add-Type -Path 'C:\Program Files\WindowsPowerShell\Modules\AzureAD\2.0.1.10\Microsoft.IdentityModel.Clients.ActiveDirectory.dll' $authContext3 = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList "https://login.windows.net/michev.onmicrosoft.com" $plat = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters -ArgumentList "Auto" $authenticationResult = $authContext3.AcquireTokenAsync("https://outlook.office365.com", "fb78d390-0c51-40cd-8e17-fdbfab77341b", "urn:ietf:wg:oauth:2.0:oob",$plat);
Once you get the token, you can issue standard web requests against the corresponding endpoints. And in case you are wondering which endpoint you need and the exact syntax to use, you can easily obtain this information by running the corresponding new cmdlet with the -Debug switch. Here’s an example:
And here’s an example on how to get a list of all the mailboxes via the REST endpoint:
$authHeader = @{'Authorization'=$authenticationResult.Result.CreateAuthorizationHeader()} $mailboxes = Invoke-RestMethod -Method Get -Uri "https://outlook.office.com/adminApi/beta/xxxxxxxx-352a-4eda-bece-09d0684d0cfb/Mailbox" -Headers $AuthHeader $mailboxes.value
As another example, we can get the properties for a single mailbox:
Invoke-RestMethod -Method Get -Uri "https://outlook.office.com/adminApi/beta/xxxxxxxx-352a-4eda-bece-09d0684d0cfb/Mailbox('vasil@xxxxxx.info')" -Headers $AuthHeader @odata.context : https://outlook.office.com/adminApi/beta/xxxxxxxx-352a-4eda-bece-09d0684d0cfb/$metadata#Mailbox/$entity @odata.id : https://outlook.office.com/adminApi/beta/xxxxxxxx-352a-4eda-bece-09d0684d0cfb/Mailbox(xxxxxxxx-888c-4b85-8871-c9766cb4791b') @odata.editLink : https://outlook.office.com/adminApi/beta/xxxxxxxx-352a-4eda-bece-09d0684d0cfb/Mailbox(xxxxxxxx-888c-4b85-8871-c9766cb4791b' ExternalDirectoryObjectId : xxxxxxxx-888c-4b85-8871-c9766cb4791b UserPrincipalName : vasil@xxxxxx.info Alias : vasil DisplayName : Vasil Michev EmailAddresses : {smtp:vasil@sb1.xxxxxx.info, SPO:SPO_xxxxxxxx-e473-451a-85e9-097d3c08307e@SPO_xxxxxxxx-352a-4eda-bece-09d0684d0cfb, SIP:vasil@xxxxxx.info, smtp:vasil@xxxxxx.onmicrosoft.com...} PrimarySmtpAddress : vasil@xxxxxx.info RecipientType : UserMailbox RecipientTypeDetails : UserMailbox Identity : vasil Id : vasil ExchangeVersion : 0.20 (15.0.0.0) Name : vasil DistinguishedName : CN=vasil,OU=michev.onmicrosoft.com,OU=Microsoft Exchange Hosted Organizations,DC=EURPR03A001,DC=prod,DC=outlook,DC=com OrganizationId : EURPR03A001.prod.outlook.com/Microsoft Exchange Hosted Organizations/michev.onmicrosoft.com - EURPR03A001.prod.outlook.com/ConfigurationUnits/michev.onmicrosoft.com/Configuration Guid : xxxxxxxx-4e45-4c28-a80f-b57b7441490f
And so on. Now, it goes without saying that this method is not supported in any way, so you should not use it in production. But, the samples above illustrate the inner workings of the new cmdlets, and they also hint what you can expect from the future Graph API endpoints for Exchange Online. To get more details on this as well as other tips on using the new cmdlets, join me and fellow MVP Ingo Gegenwarth on February 5th for the Working with the new Exchange Cmdlets webinar.
Amazing, thank you so much!
Hey Vasil,
Great post, I’ve been hanging out for something like this.
Considering that it’s now possible to connect to exchange online using the V2 module with a certificate in powershell, is it also possible to connect to the API using certificate? This would be phenomenal if possible.
It is, I demoed this in our latest webinar: https://resources.quadrotech-it.com/webinar/introducing-cba-for-exchange-online-remote-powershell?_ga=2.177234981.102594415.1596454639-1571685090.1591285272
Amazing, thank you so much!
How do I access a Shared mailbox messages using API
EWS or the Graph API both work just fine for this scenario.
Is it possible to get the Public folder mailbox list using rest api’s?
No, PF mailboxes aren’t currently returned via the REST cmdlets/API.
Thanks vasil for prompt reply.
Thanks Vasil,
Actually I managed to dig Sharepoint via powershell, but Exchange is somehow (old commands) are different story.
Hi,
Thanks for your explanation, is there any I can call those endpoint in my Java application ? as I need to get list of all shared mailboxes and the only way I found is using those new cmdlets, but I did a bit fiddler and see the request / response, and login session of course and can’t get access token valid for AdminAPI so calling to : https://outlook.office365.com/adminapi/beta/xxxx/Mailbox?RecipientTypeDetails=SharedMailbox reponses in 401.
Please advise, if that API can’t be used what can be alternative ?
Thanks !!!!
The article above gives you an example on how to get a token via the ADAL library, should be straightforward to do it in Java as well. Apart from that you need actual permissions in Exchange Online.
Well, I’m getting the token, but it’s only for those scopes: “Calendars.ReadWrite Calendars.ReadWrite.All Contacts.ReadWrite Contacts.ReadWrite.All EWS.AccessAsUser.All Files.ReadWrite Files.ReadWrite.All full_access_as_user Group.Read.All Group.ReadWrite.All Mail.ReadWrite Mail.ReadWrite.All offline_access Tasks.Read Tasks.ReadWrite User.Read.All User.ReadBasic.All” and I can’t get it like in powershell : “scope=AdminApi.AccessAsUser.All FfoPowerShell.AccessAsUser.All RemotePowerShell.AccessAsUser.All”
Yeah, you need to get it for the EXACT application that is listed above, not for any custom apps you’ve registered. MS is working on providing a support for the latter, stay tuned.
So I tried to fiddler Get-Mailbox (prev generation command) to see if it’s uses different API , but somehow it’s not captured by fiddler.
It doesn’t use Graph, you cannot get much out of Fiddler there as the actual request is executed on the backend and only “proxied” via PowerShell. If you want to dig into it: https://www.michev.info/Blog/Post/2946/using-fiddler-to-examine-remote-powershell-sessions
Pingback: Using Fiddler to examine remote PowerShell sessions | Blog
Hi, Is it possible to use the api with client_credentials grant_type.
If so how can we set the api permissions for the application?
Thanks.
Nope, PowerShell always runs in the context of a user.
Hi, Trying the api I am getting an error The user … isn’t assigned any management roles
Which roles are required and how do I set them.
Thanks.