This is an extension on the information provided by @stukey, which is already graat. Instead of creating your own function to retrieve an access token, one can use the MSAL.PS library. This module can simply be installed from the PowerShell Gallery:
Install-Module -Name MSAL.PS
Configure Azure app
When you configure your "App Registration" in Azure you can use the following settings. This will allow you to use Integrated Windows Authentication and avoids storing passwords in your code (useful when running Windows Scheduled Tasks as a specific user to run your scripts):
- Authentication > Advanced Settings > Treat application as a public client: Yes

Add the scope "EWS.AccessAsUser.All" in the section "API Permissions" (it can be found within the last option "Supported legacy API's: Exchange"):

Request token
When all this is configured you can request a new token when logged on with the correct Windows account that has Full control
exchange permissions on the desired mailbox:
$msalParams = @{
ClientId = $azureClientId
TenantId = $azureTenantId
Scopes = "https://outlook.office.com/EWS.AccessAsUser.All"
IntegratedWindowsAuth = $true
}
Get-MsalToken @msalParams
It might be required to add the switch -Interactive
, so you can consent to the proposed scopes. This will only need to be done once.
Now that a valid token is acquired a refresh of the token can simply be done with the -Silent
switch. This will get a valid token form the cache or request a new token when it's no longer valid:
$msalParams = @{
ClientId = $azureClientId
TenantId = $azureTenantId
Scopes = "https://outlook.office.com/EWS.AccessAsUser.All"
Silent = $true
}
Get-MsalToken @msalParams
It would be great if both steps above can be combined into one call. For this I opened an issue.
Use the token with Exchange Web Services
$EWS = 'C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll'
Import-Module -Name $EWS -EA Stop
$Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList 'Exchange2013_SP1'
$Service.Url = 'https://outlook.office365.com/EWS/Exchange.asmx'
$Service.UseDefaultCredentials = $false
$msalParams = @{
ClientId = $azureClientId
TenantId = $azureTenantId
Scopes = "https://outlook.office.com/EWS.AccessAsUser.All"
}
$token = Get-MsalToken @msalParams
$Service.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]$token.AccessToken
Hopefully this will help others struggling with the same issues we did.