Skip to main content

Using the Office365/Exchange 2016 REST API to access Mailbox data using PowerShell part 1

The Outlook REST API 's https://dev.outlook.com/ which are part of Office365 and Exchange 2016 is one of the ways new feature are being delivered for Mailbox clients which previously where delivered via EWS operations. They are also part of the Graph API https://graph.microsoft.io/en-us/docs which is Microsoft's envisioned unified data access API that has the ultimate goal of allowing you to access all your data endpoints via a single interface/endpoint.

In this series of posts I'm going to be looking at writing a PowerShell module that uses the REST API to access Mailbox data and some of the new Exchange features like Groups and the focused Inbox. To keep things simple and flexible I'm not going to use any helper libraries (like the ADAL library or the Outlook Services Client) which I hope will make the script as portable and easy to use as possible with the one downside of while making the code a little more complex  I'm going to use the System.Net.HttpClient classes for greater flexibility as apposed the native PowerShell Rest interfaces.

Getting started

Compared to EWS where there was very little up front configuration necessary to get going (eg in most case just supply a username and password) for the REST API's there is a little bit of configuration that needs to be done.
To use the new REST endpoint you need to use oAuth authentication which means instead of a username and password being included as a header which each request to the server like in Basic Authentication you use an Access Token which is only valid for an hour. A Refresh Token can be used to renew the Access Token when it expires. Tokens offer a big security advantage over using a UserName and Password but still should be treated as if they where a username and password in regards to storage and access as they can still be exploited in the same way. This is an extreme simplification of the oAuth, there is some good documentation sources but be careful of those that discuss Modern Authentication and the ADAL library as they tend to abstract away some the real technical side of understanding what's happening with Token Auth. Personally I like https://docs.microsoft.com/en-gb/azure/active-directory/develop/active-directory-authentication-scenarios and https://msdn.microsoft.com/en-us/office-365/get-started-with-office-365-management-apis as these look more at the underlying way the protocols work.

To use oAuth to authenticate you need to create an Application registration (which gives you the clientId) to use for your scripts or authorize somebody else's (which wouldn't be recommended).  There are plenty of good walk throughs on creating app registrations using the Azure console this one is quite good https://github.com/jasonjoh/office365-azure-guides/blob/master/RegisterAnAppInAzure.md . For scripting generally you want to create a Native App registration and use the Out of Band Call-back urn:ietf:wg:oauth:2.0:oob . One of the big advantages of using oAuth with the new REST interfaces is the authentication scopes which allow you to restrict an application/script to just being able to access the resources you want. Eg if this app is going to just access contacts data then you just enable the authentication scope that allows access to contacts data without allows access to any other Mailbox items.

Authenticating as a User or Application

In EWS and MAPI authentication is always done in the context of the User if you want to access a Mailbox other then that of security context you are using then Delegation would allow that or you could configure Application Impersonation using RBAC which means you could impersonate the owner of any mailbox you wanted to access. There is no Impersonation in the REST API but in Azure you can use what they term the Daemon or Server Application scenario or App-Only tokens which are documented  https://docs.microsoft.com/en-gb/azure/active-directory/develop/active-directory-authentication-scenarios#daemon-or-server-application-to-web-api and https://msdn.microsoft.com/en-us/office/office365/howto/building-service-apps-in-office-365 . In the current interaction of the module I don't cover this Authentication scenario but will in future posts and interactions.

What you get out of the app registration process is a ClientId to use in your script.

Down to coding

For the Authentication code in my module I've used the pretty cool  Show-AuthWindow function from https://foxdeploy.com/2015/11/02/using-powershell-and-oauth/ and https://blogs.technet.microsoft.com/ronba/2016/05/09/using-powershell-and-the-office-365-rest-api-with-oauth/ which does the job of presenting the Azure logon box, any user\tenant consents that are necessary and return back an Auth code that can then be used to get an Access Token. With my implementation I've put all the configurable variables into a separate function to call eg

function Get-AppSettings(){
        param( 
        
        )  
  Begin
   {
            $configObj = "" |  select ResourceURL,ClientId,redirectUrl
            $configObj.ResourceURL = "outlook.office.com"
            $configObj.ClientId = "5471030d-f311-4c5d-91ef-74ca885463a7"
            $configObj.redirectUrl = "urn:ietf:wg:oauth:2.0:oob"
            return $configObj            
         }    
}

This makes the ClientId, ResourceURL and redirect easy to configure

The rest of the code is pretty straight forward setting up and using the HTTPClient object to make the necessary REST GET's and POSTs. I've included a number of functions that use the MailboxSetting https://msdn.microsoft.com/office/office365/APi/mail-rest-operations#GetAllMailboxSettings you can break those down into Getting the Oof (or Automatic Replies), timezone etc. Because these are just simple http GET's the code to get the information and parse the JSON results is pretty simple. I've included a sample Get-ArchiveFolder function that demonstrates stacking requests to Get the new Archive Folder https://support.office.com/en-us/article/Archive-in-Outlook-2016-for-Windows-25f75777-3cdc-4c77-9783-5929c7b47028?ui=en-US&rs=en-US&ad=US which was introduced recently. To get the Id of an Archive Folder in a Mailbox you make a request to https://outlook.office.com/api/v2.0/Users('$MailboxName')/MailboxSettings/ArchiveFolder and then you use the result returned to get the Folder in question which might be useful if you tracking usage stats or want to copy an item into the archive.  I've put a copy of the module here (which is a work in progress) https://github.com/gscales/Powershell-Scripts/blob/master/RestHttpClientMod.ps1


Popular posts from this blog

Testing and Sending email via SMTP using Opportunistic TLS and oAuth in Office365 with PowerShell

As well as EWS and Remote PowerShell (RPS) other mail protocols POP3, IMAP and SMTP have had OAuth authentication enabled in Exchange Online (Official announcement here ). A while ago I created  this script that used Opportunistic TLS to perform a Telnet style test against a SMTP server using SMTP AUTH. Now that oAuth authentication has been enabled in office365 I've updated this script to be able to use oAuth instead of SMTP Auth to test against Office365. I've also included a function to actually send a Message. Token Acquisition  To Send a Mail using oAuth you first need to get an Access token from Azure AD there are plenty of ways of doing this in PowerShell. You could use a library like MSAL or ADAL (just google your favoured method) or use a library less approach which I've included with this script . Whatever way you do this you need to make sure that your application registration  https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-

How to test SMTP using Opportunistic TLS with Powershell and grab the public certificate a SMTP server is using

Most email services these day employ Opportunistic TLS when trying to send Messages which means that wherever possible the Messages will be encrypted rather then the plain text legacy of SMTP.  This method was defined in RFC 3207 "SMTP Service Extension for Secure SMTP over Transport Layer Security" and  there's a quite a good explanation of Opportunistic TLS on Wikipedia  https://en.wikipedia.org/wiki/Opportunistic_TLS .  This is used for both Server to Server (eg MTA to MTA) and Client to server (Eg a Message client like Outlook which acts as a MSA) the later being generally Authenticated. Basically it allows you to have a normal plain text SMTP conversation that is then upgraded to TLS using the STARTTLS verb. Not all servers will support this verb so if its not supported then a message is just sent as Plain text. TLS relies on PKI certificates and the administrative issue s that come around certificate management like expired certificates which is why I wrote th

The MailboxConcurrency limit and using Batching in the Microsoft Graph API

If your getting an error such as Application is over its MailboxConcurrency limit while using the Microsoft Graph API this post may help you understand why. Background   The Mailbox  concurrency limit when your using the Graph API is 4 as per https://docs.microsoft.com/en-us/graph/throttling#outlook-service-limits . This is evaluated for each app ID and mailbox combination so this means you can have different apps running under the same credentials and the poor behavior of one won't cause the other to be throttled. If you compared that to EWS you could have up to 27 concurrent connections but they are shared across all apps on a first come first served basis. Batching Batching in the Graph API is a way of combining multiple requests into a single HTTP request. Batching in the Exchange Mail API's EWS and MAPI has been around for a long time and its common, for email Apps to process large numbers of smaller items for a variety of reasons.  Batching in the Graph is limited to a m
All sample scripts and source code is provided by for illustrative purposes only. All examples are untested in different environments and therefore, I cannot guarantee or imply reliability, serviceability, or function of these programs.

All code contained herein is provided to you "AS IS" without any warranties of any kind. The implied warranties of non-infringement, merchantability and fitness for a particular purpose are expressly disclaimed.