Hero Banner

Secure Application Model

Learn and ask questions on how to implement secure application model

Level 2 Contributor

Exchange Online and the Secure App Model

Am I missing something in that I cannot see a way to implement it. A lot of my automation relies on the ability to see things like transport rules and Exchange configuration settings that come out of the Exchange Online Powershell cmdlets.


Is this stuff exposed in the Graph API or ANY API? I can't see it anywhere. Are there plans to update the Exchange Online Powershell Module to support the Secure App Model before 1st of August?


Re: Exchange Online and the Secure App Model

Hi @Gavsto


Currently the Exchange Online PowerShell module does not support DAP when MFA is enabled. You can find more information about this here. The Exchange Online team is working to resolve this issue as quickly as possible. Unfortunately I do not have any additional information to share just yet. As I learn more I will be sure to share it with you.

Isaiah Williams
Cloud Technology Strategist | US – One Commercial Partner
Level 4 Contributor

Re: Exchange Online and the Secure App Model

Sorry for jumping in and for the late reply (I was on holidays when this was announced early July and I'm just back now).


So what is the solution for Partners using Delegated Admin to access our clients' Exchange Online via PowerShell? In another thread it was mentioned that we shoould create an Admin in each client's tenant and use that - use 100's of separated admin accounts? That seems like a worse solution.


I have various automations that run daily that need to connect to all our client's Exchange Orgs to make changes, I can't even envision a simple method to manage all the changes so we can still access all clients alonng with separate usernames/passwords for each.


Can we avoid the issue with Azure AD IP Based Conditionl Access policies and still be in compliance? (all connections come from our secured servers)


Or will the Exch Online team have this fixed by Aug 1st?!


Level 2 Contributor

Re: Exchange Online and the Secure App Model

I am keen to get an answer to this too because I have heavy reliance on Exchange Powershell cmdlets across hundreds of different clients too.


Re: Exchange Online and the Secure App Model

@Gavsto and @sansbacher our documentation has been updated to include details for a workaround for this limitation. You can find the details for this workaround here. The Exchange Online team is actively developing a solution for this limitation, but it will be some time before it is available. We will be sure to keep everyone informed as progress is made.

Isaiah Williams
Cloud Technology Strategist | US – One Commercial Partner
Level 4 Contributor

Re: Exchange Online and the Secure App Model

Thanks @idwilliams


So I'm clear: the workaround is to create a new AzureAD user in OUR (CSP/Partner) tenancy, assign it AdminAgents privleges (in the PartnerCenter) and not using it to perform an interactive login?


How is that going to work when MS enforces the technical requirement that ALL accounts in our CSP/Partner tenantancy have MFA enabled with the Baseline Policies? Or is the fact that it isn't logged into interactively mean it doesn't have the MFA policy applied and will continue to work with Exchange Online Delegated Admin Privileges? Essentially "fly under the radar"? [I actually have an account now I use only from unattended scripts, so it may continue working? Or must it be an all new account?]


This is confirmed to work? Will this account also work to connect to AzureAD?


A previous suggestion had been to create an Exchange Admin in client/customer tenant and manage Exch Online that way - is that no longer suggested?

Level 2 Contributor

Re: Exchange Online and the Secure App Model

I have to say that Microsoft's response to these changes, especially related to Exchange Online has been absolutely inadequate and sub-standard.


I'm left in a position now where our clients are actually in a WORSE position with the implementation of these new security measures because none of our custom security monitoring works any more.


You come back with half-baked, hacked together bypasses that go directly against your own security guidance on how you are going to be enforcing these security standards.


It's disgraceful and Microsoft should be ashamed of themselves. They've had YEARS now to upgrade the Exchange Online module.




Re: Exchange Online and the Secure App Model

@sansbacher, the workaround for Exchange Online will continue to function with technical enforcement.  The account you created for unattended scripting will continue to function as well as long as the account has never been used to complete an interactive login.  With that said, this workaround should be viewed only as a temporary workaround.  Support for delegated admin priviledges will be added to the Exchange Online powershell module in the future and this workaround will be removed.  Your unattended scripts should be modified to support the secure application model to ensure long-term support.


The previous suggestion of creating an account in each client/customer tenant is no longer recommended.

Level 4 Contributor

Re: Exchange Online and the Secure App Model

Thank you @daokeefe - I appreciate the response (though I have to say that in general I agree with @Gavsto regarding how all this has been handled, esp. as it relates to the Exch Online PowerShell)


I have an existing unattanded service account, it was created a while ago so I don't know if it was ever logged into interactively, it hasn't been recently since MFA was turned on. If it fails to work I will create another one.


I hope that when proper Delegated Admin Privileges are added to the Exchange Online PowerShell module that we'll get advance notice before the work-around is disabled so that we can test the new module with the Secure App Model and our scripts (since we won't know exactly how it works until you deliver it).

ALSO: how will we be notified when the ExO module has been updated?


NOTE: I have tested the Secure App Model, and I found it works with the older MsOnline module, but not the newer AzureAD module. I hope that is fixed too. (and add the MFA controls to AzureAD at the same time)


Sorry for my late reply, I was on holidays - but I'm back now!



Re: Exchange Online and the Secure App Model

@sansbacher once the issue Exchange Online PowerShell is resolved, we will post an announcement through this community. Also, there will be a number of additional mechanisms we use to communicate this release. Once we get closer to the update being release, I will be able to comment more percisely on how this announcement will be handled. 


As it relates to the Azure AD PowerShell module, I have confirmed it does work with the Secure Application Model. If you can let us know what issues you encountered we will be glad to see if we can help resolve the issue. 

Isaiah Williams
Cloud Technology Strategist | US – One Commercial Partner
Level 2 Contributor

Re: Exchange Online and the Secure App Model

There is no update yet for the Exchange Online modules, making it very difficult to run automated jobs except for the workaround we've been given before - Which has also been removed from the docs so it is safe to assume it is no longer allowed to use this workaround.


We require automated access to the Exchange Online PowerShell, using delegated permissions to script specific events without an engineer touching these automated PowerShell scripts and logging in under each tenant.


Next to this - other modules such as the Azure-AD module do work when using the secure app model for our own tenant, but not for delegated access tenants. The documentation is also -extremely- unclear how to set this up for all tenants under our administration via delegated access, but so far every reaction Microsoft is stating to look at the documentation.


It seems like this entire exercise has been a panicked move by Microsoft and there is no clear path for automators, CSPS, and MSP's to actually access all the resources (Exchange online, Microsoft Teams, Azure AD) of all the delagated tenants we have access to using automation via PowerShell. 


Please update the documentation to match the exact use cases of the Secure Application Model to show how to access resources in delegated tenants, with examples of each module that supports the Secure App Model, because right now I believe this is not possible due to a Microsoft oversight.


Re: Exchange Online and the Secure App Model

@KelvinTegelaar : Reg. Exchange Online I'm currently researching the updated status - so far the workaround mentioned (use an account which never has been used for an interactive logon) does still work. There are several updates to the documentation in the works, afaik this aspect is moved to a new article which has not been published yet.


For the other questions, like AzureAD module - it is possible to get specific guidance when raising an advisory request, Partner with Action Pack, Silver or Gold competency level get advisory hours as technical benefit and then the scenario and potential solution can be discussed 1:1 - see aka.ms/technicaljourney or the "PreSales and Deployment Planning" support options at partner.microsoft.com/support. Also an email to askpts@microsoft.com does work to raise a case in this team (While I'm from this team, I miss the required expertise to answer right here and we can invest more time into this when you raise a ticket).


However, it is true that there might still be services/scenarios which do not play well with the MFA requirements and you are also correct that security requirements had to be introduced before there is a perfect answer from every related product team.




Re: Exchange Online and the Secure App Model

And I was just informed about an updated article on this, available here: https://docs.microsoft.com/en-us/powershell/partnercenter/multi-factor-auth?view=partnercenterps-2.0#exchange-online-powershell 


Edit#2: This method requires you to go through interactive sign-in once to get the refresh token, then you can get access token for each customer without the need to go through interactive sign-in again. This method does not support the before mentioned workaround where you create a user account that was never used for an interactive sign-in. 


Edit: New/recent ExO Powershell version should be downloaded for this.

Level 2 Contributor

Re: Exchange Online and the Secure App Model

Awesome! this is a fantastic and welcome update.


Just to clarify: We have to get a refresh token per tenant under our administration, and not just a single refresh token for our tenant, which should have delegated access to each of the other locations? 


Thanks Janosch, This is good news and I am glad you're also acknloweding that we got limited in our work a bit by the sudden move to the secure application model.


Re: Exchange Online and the Secure App Model

Yes, the way the token based authentication works is that there is a token for each customer tenant: however, you do the interactive sign-in only once to get the token for your Partner Center user, with this token you can get the token for each customer tenant without going through the interactive sign-in again - so similar to other scenarios with secure app model. 

Level 2 Contributor

Re: Exchange Online and the Secure App Model

@KelvinTegelaar @JanoschUlmer 


Do either of you have any example of how you would utilise this from an automation perspective. Is an interactive login still required each time a script is run?


Example - lets say I want to run through every mailbox with Get-EXOMailbox at every business we support (100s of different tenants). What would be the best method to use?

There's a DelegatedOrganization switch listed at https://docs.microsoft.com/en-gb/powershell/module/exchange/powershell-v2-module/connect-exchangeonline?view=exchange-ps but it doesn't work. If I do Connect-ExchangeOnline -DelegatedOrganization "myclient.onmicrosoft.com", it prompts me for login, and once logged in I run Get-EXOMailbox and I end up with my own tenants mailbox and not that of the delegated org.


Re: Exchange Online and the Secure App Model

@Gavsto : Unfortunately currently I won't have sufficient time to test this and give detailed guidance - for now I can only refer to the documentation and exaples on how to work with the access tokens.


There is the option you raise an advisory request to get 1:1 guidance from a Partner Consutlant that is more experienced in Exchange Online: askpts@microsoft.com or use this link to raise a request Online.

Level 2 Contributor

Re: Exchange Online and the Secure App Model

Opened an issue, as it seems the ParterCenter module is broken and does not generate credentials for Exchange right now: https://github.com/microsoft/Partner-Center-PowerShell/issues/186

Level 2 Contributor

Re: Exchange Online and the Secure App Model

So the module has been updated, but there is still a problem with the documentation. 


I've run the following:

$token = New-PartnerAccessToken -ApplicationId 'a0c73c16-a7e3-4564-9a95-2bdf47383716' -Scopes 'https://outlook.office365.com/.default' -Tenant 'xxxx-xxxx-xxxx-xxxx' -UseDeviceAuthentication

and I have a refresh token generated for Exchange, so far so good. Now if I follow the rest of the documentation I'll execute the following to create a per-tenant refresh code and start a session:

$refreshToken = '<RefreshTokenValue>'
$upn = '<UPN-used-to-generate-the-refresh-token>'

$token = New-PartnerAccessToken -ApplicationId 'a0c73c16-a7e3-4564-9a95-2bdf47383716' -Credential $credential -RefreshToken $refreshToken -Scopes 'https://outlook.office365.com/.default' -ServicePrincipal -Tenant 'ID-OF-DELEGATED-TENANT'

but $credential has not been set anywhere, when trying the applicationid+secret I get the error:

New-PartnerAccessToken : AADSTS7000215: Invalid client secret is provided.

When trying the UPN+Refresh token I get the same error. I believe the documentation is missing a little bit.


Re: Exchange Online and the Secure App Model


Just forwarding the ad hoc response from an expert:


The root cause for this issue is that the Credential and ServicePrincipal parameter should not be used. It is included in our documentation because with everything else the Azure AD application exists in the partner's tenant instead of a foreign one. If they remove those parameters it should work as expceted
Level 2 Contributor

Re: Exchange Online and the Secure App Model



See the following blog for a ready-made solution: https://www.cyberdrain.com/connect-to-exchange-online-automated-when-mfa-is-enabled-using-the-secureapp-model/


It took some work, and some argueing but with the current version everything is working. @JanoschUlmer Thank you for your help, The documentation will still need some updates but my blog contains those for anyone looking right now.



Level 4 Contributor

Re: Exchange Online and the Secure App Model

@KelvinTegelaar Stellar work, thanks so much! I've been somewhat absent from all this MFA/CSP stuff since before Technical Enforcement on Nov 18th - busy with other stuff. But your blog post basically had everything I needed!


I was able to connect to Exchange Online of one of our Customers using Delegated Permissions without any user interaction! I now have to update all my scripts...


But I did have a problem with Azure AD, connecting to Azure AD of Customers we have delegated admin rights to. But I worked it out.


Connecting to our CUSTOMERS with Msol is fairly straight forward, use the Connect-MsolService commands as listed at the end of Kelvin's blog post to connect to YOUR (eg. CSP) Msol service, then Get-MsolPartnerContract will list all YOUR Customers you have DELEGATED permissions to. You can then use a foreach ($customer in $Customers) {} loop.
Inside the foreach you can then use any Msol command AND specify their TenantID, eg: Get-MsolUser -TenantId $Customer.TenantId will show the CUSTOMER'S users, not yours. You need to add -TenantId to all Msol commands since you are connected to your Msol service endpoint (but you have delegated permissions to your Customers)


For AzureAD it was slightly more complicated: I could get MY internal (eg. CSP) Users, but not my CUSTOMER's Users that I had Delegated permissions to, I would get an error like:
Get-AzureADUser : Error occurred while executing GetUsers
Code: Request_BadRequest
Message: Invalid domain name in the request url.


The solution for Azure AD is:
Connect to AzureAD as listed in Kelvin's blog post, this will connect to YOUR (eg. CSP) Azure AD
Get all your Customers that you have Delegated Admin rights to with: Get-AzureADContract
Then Disconnect-AzureAd (will disconnect from your AzureAD)
You will need (just like the Exch Online code): $upn = 'UPN-Used-To-Generate-Tokens'
Then in your foreach ($customer in $Customers) {} loop you must obtain NEW AAD and Graph Tokens for the Customer's TenantId, such as:
$CustAadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $customer.CustomerContextId

# And
$CustGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $customer.CustomerContextId
Finally connect to the CUSTOMER'S AzureAD (to which you have Delegated rights):
Connect-AzureAD -AadAccessToken $CustAadGraphToken.AccessToken -AccountId $upn -MsAccessToken $CustGraphToken.AccessToken -TenantId $customer.CustomerContextId
[Note that $customer.CustomerContextId is the CUSTOMER's TenantID, which is obtained from Get-AzureAdContract (when connected to YOUR Azure AD, the first time)]

You can now run commands like Get-AzureAdUser or Get-AzureAdDomain and it will show the CUSTOMER's users/info.
Disconnect-AzureAd at the end of the loop (from the Customer's AzureAD)


More script updating for me! But at least I can now use the Secure App Model with MFA to connect to my CSP Azure AD, get all Customers, and then connect to each of my Customers' Azure AD + Exch Online to do unattended scripting.


Thanks for finally getting this all sorted out!


PS: This is using the most recent AzureAD, Msol, and PartnerCenter modules (,, and 3.0.1 respectively). No need at this point for the new preview Exchange Online V2 PowerShell module. Maybe in the future it'll make things easier.


Level 2 Contributor

Re: Exchange Online and the Secure App Model

@sansbacher Really appreciate the update!

I've been delving in to this further today but I am still hitting a brick wall.

I have my Azure AD Application created. I have my RefreshToken created. I know these work OK because delegated access works to both Exchange and MSOnline.

$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID 
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID 

Connect-MsolService -AdGraphAccessToken $aadGraphToken.AccessToken -MsGraphAccessToken $graphToken.AccessToken

Works great!


When it comes to AzureAD I am completely stuck. Previously my problem was that I couldn't get access to my client's AzureAD. I used to run Get-AzureADUsers and just see my own staff. Now I can't even see my own staff.

Get-AzureADUser : Error occurred while executing GetUsers 
Code: Authorization_RequestDenied
Message: Insufficient privileges to complete the operation.
RequestId: Redacted
DateTimeStamp: Mon, 06 Jan 2020 22:35:16 GMT
HttpStatusCode: Forbidden
HttpStatusDescription: Forbidden
HttpResponseStatus: Completed

At line:1 char:1
+ Get-AzureADUser
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-AzureADUser], ApiException
    + FullyQualifiedErrorId : Microsoft.Open.AzureAD16.Client.ApiException,Microsoft.Open.AzureAD16.PowerShell.GetUser

This is the same for any AzureAD command.

The code I am using:

$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $ApplicationCredential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $TenantID
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $ApplicationCredential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $TenantID

Connect-AzureAD -AadAccessToken $aadGraphToken.AccessToken -MsAccessToken $graphToken.AccessToken -TenantId $TenantID -AccountId $UPN

The UPN I am adding in is the UPN of the user who performed the initial consent when creating the application (my e-mail address).

Incidentally, Connect-AzureAD does return something when run:

Account                     Environment TenantId                             TenantDomain                         AccountType
-------                     ----------- --------                             ------------                         -----------
myladmin@emailaddress.co.uk AzureCloud  MyTenantIDHere    MyTenantIDHere AccessToken

Anyone have any idea how I even start to diagnose this?

I've created the application from scratch. I've tried different Global Admins. I've ran out of ideas. I wonder if MS have any input either, @JanoschUlmer 

Level 4 Contributor

Re: Exchange Online and the Secure App Model

Hi @Gavsto 

I think the main issue is that you're using -TenantId $TenantID (which is probably your TenantID) rather than -TenantId <someClientTenantID>. You need to use your tenant ID when connecting to your Azure AD, and client TenantID when connecting to a client's AzureAD (with all new AAD and Graph Tokens for the Tenant).


I have converted over all my client/delegatedAdmin Azure AD + Exchange Online scripts and they're all working unattended just fine now. Here's what I did (maybe a little verbose, I know you have Msol and ExO working, but for the benefit of anyone else...)


I used @KelvinTegelaar 's version of Create-AzureADApplication.ps1 (which is itself a modified version of @idwilliams 's script to add the Exchange Online stuff and always Consent). I did the Consenting with my account, which is a Partner Center Admin - you need it to be MFA enabled and have to Consent a few times with the script.

NOTE: The Azure AD App Redirect URI of "urn:ietf:wgRobot surprisedauth:2.0Robot surprisedob" will be added as type = Web, it needs to be changed to "Public client/native (mobile & desktop)" manually.


At the end of the script I got several values, which I've stored securely (we use PasswordState as it has an API, but Azure Vault would also work). The RefreshTokens are only good for 90 days, so you'll need to have a process of "using" them to get an AccessToken (which also returns a renewed RefreshToken) and storing that new RefreshToken - I do it weekly. I have mine saved as:


$ApplicationId         = 'e7282f0e-my-azure-ad-app-id-e7e6a479894e'
$ApplicationSecret     = 'XF+zHGx+super+secret+key+LNPiyUkylk=' | Convertto-SecureString -AsPlainText -Force
# I use my domain name Tenant Domain:
$TenantID              = 'my-msp-tenant-domain.ca'
# This format also works, and is what the script delivers
$TenantID2              = '6169ca06-my-tenat-guid-id-69acca8d2bb6'
# This one is NOT output, but you need it - it's the MFA-enabled Account you Consented with in the script:
# This is my email address / O365 UPN: $Upn = 'sansbacher@my-msp-tenant-domain.ca' # These are actually really, really long, no spaces: $RefreshToken = 'OAQABAAAAAACQN9=big=long=token=all=as=one=line=RoDlwt1oD-tW-mxRAbyAA' $ExchangeRefreshToken = 'OAQABAAA=DIFFERENT=big=long=token=all=as=one=line=O7Cm3-8gPF4l15IccyAA'


For Azure AD you need to get the AccessTokens twice - once to connect to your/company/MSP Azure AD to get all the Clients/Customers - well their TenantIDs, and then to each Customer (I suppose your could save them, but your client list could change):


# CSP Partner connection:
$credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $ApplicationSecret) $aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID $graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID Connect-AzureAD -AadAccessToken $aadGraphToken.AccessToken -AccountId $Upn -MsAccessToken $graphToken.AccessToken -TenantId $tenantID
# Find all your Customers/Clients, pick the last one: $Customers = Get-AzureADContract -All $True | select DefaultDomainName, CustomerContextID $Customer = $Customers[-1] $Customer
# Disconnect from your AzureAD Disconnect-AzureAD # Now connect to that Customer, uses the same $credential as above, but the -TenantID is of the client:
# These are Customer Specific Tokens: $CustAadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $Customer.CustomerContextId $CustGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $Customer.CustomerContextId # now connect to the CLIENT's AzureAD Connect-AzureAD -AadAccessToken $CustAadGraphToken.AccessToken -AccountId $upn -MsAccessToken $CustGraphToken.AccessToken -TenantId $customer.CustomerContextId
# Now you can work on the customer's Azure AD Get-AzureADDomain Get-AzureADUser | select -first 10 # Then: Disconnect-AzureAD when done with each Customer, unless also connecting to ExchOnline

NOTE:  You use the same $credential, but for CSP Partner (your Azure AD) you connect using your $tenantID, you can then Get-AzureADContract and see all your customers. Then Disconnect, and re-connect using the Customer's TenantID getting all NEW AccessTokens. You need to connect/disconnect using Customer Specific Tokens for each customer.


I found this whole process took longer than the old process, so your scripts will take longer. Also: AccessTokens are only good for 60 mins, so if you have a long running process for a client (eg. doing something on every User or Mailbox for a client) you may need to disconnect and re-connect when you're near 50 mins (I use a connection timer and check it at the start of the foreach ($mbx in $AllMailboxes) loop).


If you have any issues or still can't make it work, let me know and I'll see if I can help.


For the benefit of anyone else, here's how you would connect to Exchange Online PowerShell:

# Customer:
$ExchToken = New-PartnerAccessToken -ApplicationId 'a0c73c16-a7e3-4564-9a95-2bdf47383716'-RefreshToken $ExchangeRefreshToken -Scopes 'https://outlook.office365.com/.default' -Tenant $customer.CustomerContextId
$tokenValue = ConvertTo-SecureString "Bearer $($ExchToken.AccessToken)" -AsPlainText -Force
$ExchCredential = New-Object System.Management.Automation.PSCredential($upn, $tokenValue)
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell-liveid?DelegatedOrg=$($Customer.DefaultDomainName)&amp;BasicAuthToOAuthConversion=true" -Credential $Exchcredential -Authentication Basic -AllowRedirection

Import-PSSession $session

get-mailbox | select -first 10

# After each Customer:
Remove-PSSession $Session

It assumes you have already connected to your MSP Azure AD to get a list of all Customers' TenantIDs and then just want to connect to each Customer's Exch Online.  It has its own Exch specific $cred and $refreshToken.


And for completeness, MSOnline / Msol:

# CSP Partner:
$credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $ApplicationSecret)

$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID 
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID 

Connect-MsolService -AdGraphAccessToken $aadGraphToken.AccessToken -MsGraphAccessToken $graphToken.AccessToken

$Customers = Get-MsolPartnerContract | select DefaultDomainName, TenantId $Customer = $Customers[-1] $Customer # Customer: Get-MsolDomain -TenantId $Customer.TenantId Get-MsolUser -MaxResults 10 -TenantId $Customer.TenantId # No disconnect

The $credential is the same as Azure AD.  You can also use the list of Customers from your MSP, but you don't need to specifically connect to each Customer, but you DO need to add -TenantID to each *-Msol* command. There's no disconnect for Msol that I can find.

NOTE: Msol's $Customer.TenantId and AzureAD's $customer.CustomerContextId are the same.


I hope that helps someone else too! Let me know if it works or not.



Level 2 Contributor

Re: Exchange Online and the Secure App Model

@sansbacher - such a comprehensive answer. Truly appreciate the effort you have put in to that.


The TenantID I am using is mine - I'm not even attempting to get to my Client's AzureAD at the moment as when I run Get-AzureADContract it doesn't work:

Get-AzureADContract : Error occurred while executing GetContracts
Code: Authorization_RequestDenied
Message: Insufficient privileges to complete the operation.

I thought you had something with the Azure AD App Redirect URI and changing it to Public client/native (mobile & desktop)" manually. I did that but it made no difference. I am a Partner Center Admin, with MFA enabled. The consent process seems to go fine. As mentioned previously the MSOL and Exchange stuff works fine.

From the error it does look like a permission problem of some sort but no idea where to go from here.

I've attached the API Permissions in App Registrations for the created App. Could you compare them to yours and see if there's a difference?

Really appreciate the help here.