Connect to Exchange Online PowerShell with Connect-ExchangeOnline cmdlet and a service principal with client secret
Connecting to Azure with a service principal with client secret is quite simple - you can get the credentials and pass them to the Connect-AzAccount cmdlet and specify the -ServicePrincipal parameter.
$credential = Get-Credential
Connect-AzAccount -Credential $credential -TenantId "your-tenant-identifier" -ServicePrincipal
Connecting to Exchange Online however is somewhat more problematic - there is no "ServicePrincipal" parameter and using the cmdlet with just a credential and organization shows the following error.
The user is not recognized as a managed user, or a federated user.Azure AD was not able to identify the IdP that needs to process the user U/P: Wrong username
It looks like Microsoft haven't implemented the ability to use client secrets as they're not as secure as certificates (and the Connect-ExchangeOnline cmdlet has good support for certficiates).
Microsoft doesn't appear to have implemented any of their online services with any kind of consistency.
The cmdlets are all using the Microsoft Authentication Library (MSAL) under the hood which in turn creates and posts a message to the login.microsoftonline.com to generate a JWT (JSON Web Token) also seen as a bearer token so you can do this directly yourself bypassing the cmdlets and MSAL.
$clientId = "your-service-principal-app-identifier"
$clientSecret = "your-client-secret"
$tenantId = "your-tenant-id"
$tokenBody = @{
Grant_Type = "client_credentials"
Scope = "https://outlook.office365.com/.default"
Client_Id = $clientId
Client_Secret = $clientSecret
}
$tokenResponse = Invoke-RestMethod -Uri https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token -Method POST -Body $tokenBody
You can then pass this bearer (JWT) token to the Connect-ExchangeOnline cmdlet using the AccessToken parameter
Connect-ExchangeOnline -AccessToken $tokenResponse.access_token -Organization "your-organization-name.onmicrosoft.com";
You still need to use the Exchange PowerShell cmdlets rather than access the REST API directly because
- The REST API isn't public
- The REST API is in BETA (and presumable the PowerShell cmdlets will switch to production when a production API is available)
- The REST API is not a proper REST API - if you look at the endpoint the say the Get-AddressList cmdlet is called you'd expect something like GET /AddressLists - however all the cmdlets that don't start with Get-EXO* actually sent a command to this one /InvokeCommand address
https://outlook.office365.com/adminapi/beta/identifier/InvokeCommand
The inside of the message posted to this address is some JSON that includes the cmdlet being run. This is pretty poor.
{"CmdletInput":{"CmdletName":"Get-AddressList","Parameters":{}}}
While you're here why not check out our Exchange audit and documentation tool?
Comments
Post a Comment