Skip to main content

Using 2 Authentication factors (for MFA) in an unattended PowerShell Script

MFA (Multi Factor Authentication) is great at making the Authentication process more secure in Exchange Online but can be challenging in Automation scenarios. I originally wrote this code for something that I wanted to run unattended on a RasberryPi that was running PowerShell that i wanted to use MFA on and where i wanted to avoid going down the path of using the 90 day RefreshToken/device code method and I also didn't want to use App Authentication via Certificates or Client Secrets.

Interestingly while i was writing this post Microsoft just announced Certificate based Modern Auth in Exchange Online PowerShell https://techcommunity.microsoft.com/t5/exchange-team-blog/modern-auth-and-unattended-scripts-in-exchange-online-powershell/ba-p/1497387  .  This article also links to the Secure App Model https://docs.microsoft.com/en-us/powershell/partnercenter/multi-factor-auth?view=partnercenterps-3.0#exchange which is the way Microsoft are recommending you handle MFA in unattended delegate scenarios so this is an alternative to this if you can't go down that path .

One thing to note about any unattended method is that by there nature (eg because they aren't interactive) they can all potentially be unraveled by a bad actor if they make it passed the outer security of the machine where the script is running. Eg an unlocked machine or week logon security to that machine that would allow an attacker to access the stored RefreshToken/Certificate/SharedKey (no matter where they are stored or how they are encrypted). However the more factors you can put into your unattended process eg encrypting the stored cert/key etc the slower its going to be for anybody trying to unravel it. The gold standard would be an Secure Azure VM where the secrets themselves are in a KeyVault and use a managed identity but in the real world this is not always possible. In security terms you should always consider what the implications are when the security around your unattended process fails (and not if it fails). 

Factors

The two factors in my script that I'm going to be using is firstly a Username and Password which is really the only Primary Authentication method that currently lends itself to be used unattended (eg FIDO and OATH requires some level of interactivity). The additional second factor I'm using is TOTP (Time based One Time passwords) which are relatively easy to generate as they are based on https://tools.ietf.org/html/rfc6238 . Other people have already created a few Powershell functions for generating TOTP's so the one I decided to use was https://www.powershellgallery.com/packages/SecurityFever/2.2.0/Content/SecurityFever.psm1 which just requires that you pass in the SharedSecret that you get when you add a (3rd Party Authenticator)to your account in Office365 as an additional authentication method . To do this you should select to add an Authenticator application as an additional authentication method and select the "Configure app without notifications" from the screen that shows the QRCode. You then should be presented with a secret (shared)key (if it has spaces in it you will need to remove these) which you then need to feed into the Get-TimeBasedOneTimePassword cmdlet which will provide the verification code to successfully add the authenticator eg

Get-TimeBasedOneTimePassword -SharedSecret txxxxxxxxxxxx

You then need to store this sharedsecret as securely as you can as you will use this each time you want to logon to generate the TOTP factor for the authentication. A few ways of storing this is firstly use an Azure key vault, if you have a Windows machine your running it on then consider the credential store which can be used easily via another Powershell module https://www.powershellgallery.com/packages/CredentialManager/2.0 and there's a simple demo of using it https://github.com/pnp/PnP-PowerShell/wiki/How-to-use-the-Windows-Credential-Manager-to-ease-authentication-with-PnP-PowerShell . (I would suggest you put a second layer of encryption on top of this so whatever goes into the credential store is also encrypted)

MFA Code

So far I've been using a whole bunch of other peoples code but now comes to the bit i wrote which does the MFA authentication using OpenId connect https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc and then gets an AccessToken once an authorization_code is acquired. This code is relatively straight forward it starts the normal browser based authentication flow maintaining the session using Invoke-WebRequest's -WebSession parameter and parses out the context, flow and canary tokens from the response which are needed in various parts of the process. For the additional authentication factor the TOTP is used.

Example 

While my code was written for EWS primarily running on a Rasberry PI a more relevant sample is a Exchange Online PowerShell connection eg 

So this simple example uses the CredentialManger PS module to grab a ShareSecret from the credential store and generate a TOTP and then you have a normal set of PSCredentials and the "BasicAuthToOAuthConversion=true" query-string does the rest.

A few things to remember is that Access Tokens are only good for 1 hour so if you expect your script to run for longer then this you will need to put in a method of refreshing the Token (or just generate a new access token). 

I've put the code for the AzureMFAOTPv2 module on GitHub here https://github.com/gscales/Powershell-Scripts/blob/master/AzureMFAOTPv2.ps1

 






Popular posts from this blog

Export calendar Items to a CSV file using EWS and Powershell

Somebody asked about this last week and while I have a lot of EWS scripts that do access the Calendar I didn't have a simple example that just exported a list of the Calendar events with relevant information to a CSV file so here it is.

I've talked on this one before in this howto  but when you query the calendar folder using EWS you need to use a CalendarView which will expand any recurring appointments in a calendar. There are some limits when you use a calendarview in that you can only return a maximum of 2 years of appointments at a time and paging will limit the max number of items to 1000 per call. So if you have a calendar with a very large number of appointments you need to break your query into small date time blocks. In this example script I'm just grabbing the next 7 days of appointments if you want to query a longer period you need to adjust the following lines (keeping in mind what I just mentioned)

#Define Date to Query
$StartDate = (Get-Date)
$EndDate = (Ge…

EWS Managed API and Powershell How-To series Part 1

I thought I'd start the year with a series of posts that goes back over the basics of using the EWS Managed API from Powershell and provides a modular remarked example that you can easily cut and paste to build your own scripts. Along the way in this series I'll show a whole bunch of examples around specific things.

As a starting point for versions this will be Powershell Version 2.0  and the EWS Managed API 1.1 (which will soon change to 1.2 once released) http://www.microsoft.com/download/en/details.aspx?id=13480.

The starting point for any EWS script your going to write is connecting to Exchange for which there are three important pieces of information you will need. Firstly you need to know the version of Exchange your running in this script its going to be held in the following variable

$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1

Other valid values for Exchange 2007 would be

$ExchangeVersion = [Microsoft.Exchange.WebServices.…

Microsoft Teams Private Chat History Addin for Outlook

Being somebody who is transitioning across from Skype for Business to Teams one of things I missed the most (and found the most frustrating) is the lack of the ability in Outlook and OWA to view the conversation history from Online meetings and private chats in Microsoft Teams. This is especially frustrating when you have an external meeting and your sent an IM that contains some vital information for what you need to do. This information is tracked in your mailbox for compliance reasons in the Teams Chat folder but this folder is hidden so it not accessible to the clients and must be extracted by other means eg. Most people seem to point to doing a compliance search if you need this data https://docs.microsoft.com/en-us/microsoftteams/security-compliance-overview .

Given that the information is in my mailbox and there shouldn't be any privacy concern around accessing it I looked at a few ways of getting access to these TeamsChat messages in OWA and Outlook the first way was using …
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.