Running Office365 Powershell scripts cross tenant

When you manage multiple tenants or have a Microsoft Partner account to manage a lot of tenants it often gets annoying having to redeploy the same scripts to each tenant over and over. You can try using the MSOL commands but most of the times the scripts you are trying to run are Exchange, Skype for business, or Teams scripts, and you’re not able to run these just by using the Azure Active Directory Module for PowerShell.

The great thing is that Microsoft actually has a perfect solution for this by using your partner credentials cross tenant. You can change the session URL to match the specific client you are trying to manage, this means you can deploy scripts across all clients with relative ease when using the following scripts.

To get started on this, I’ll demonstrate how to get all mailbox sizes across your multiple tenants.
First, we’ll have to connect to Office365 by using the MSOL Microsoft Azure Active Directory Module for Windows PowerShell

connect-msolservice
$clients = Get-MsolPartnerContract -All

When we’re connected, our client list is filled in $clients. This means we can loop trough each client and perform actions for them. In our case we’ll simply be gathering information, but you could also change settings such as disabling clutter, or enabling other functionality.

foreach ($client in $clients) {
$ClientDomain = Get-MsolDomain -TenantId $client.TenantId | Where-Object {$_.IsInitial -eq $true}
    Write-host "Logging into portal for $($client.Name)"
    $DelegatedOrgURL = "https://ps.outlook.com/powershell-liveid?DelegatedOrg=" + $ClientDomain.Name
    $ExchangeOnlineSession = New-PSSession -ConnectionUri $DelegatedOrgURL -Credential $credential -Authentication Basic -ConfigurationName Microsoft.Exchange -AllowRedirection
    Import-PSSession -Session $ExchangeOnlineSession -AllowClobber -DisableNameChecking

Now that we’re connected to the Exchange PowerShell session for this client we can run whaterver Exchange commands we’d like. in our case, getting the mailboxes and respective size:

Get-Mailbox | Get-MailboxStatistics | Select-Object DisplayName, IsArchiveMailbox, ItemCount, TotalItemSize | format-table

When we’ve performed our commands, we do need to destroy our session as PowerShell sessions on Office365 can be rate limited.

Remove-PSSession $ExchangeOnlineSession
}

See that final curly bracket? With that one we close our for-each loop, Simply put we’re telling PowerShell that the loop is over, and it can continue with the next client in the list. If we put all of this together our script will look like this:

$credential = Get-Credential
connect-msolservice -Credential $credential
$clients = Get-MsolPartnerContract -All
foreach ($client in $clients) {
    $ClientDomain = Get-MsolDomain -TenantId $client.TenantId | Where-Object {$_.IsInitial -eq $true}
    Write-host "Logging into portal for $($client.Name)"
    $DelegatedOrgURL = "https://ps.outlook.com/powershell-liveid?DelegatedOrg=" + $ClientDomain.Name
    $ExchangeOnlineSession = New-PSSession -ConnectionUri $DelegatedOrgURL -Credential $credential -Authentication Basic -ConfigurationName Microsoft.Exchange -AllowRedirection
    Import-PSSession -Session $ExchangeOnlineSession -AllowClobber -DisableNameChecking
    Get-Mailbox | Get-MailboxStatistics | Select-Object DisplayName, IsArchiveMailbox, ItemCount, TotalItemSize | format-table
    Remove-PSSession $ExchangeOnlineSession
}

So that’s it. you can easily replace the command for something as disabling clutter, focused inbox, enable auditing, etc. The great thing is that by combining this with an Azure Function gives your the ability to automatically apply your preffered settings to all clients. Happy PowerShelling!

Recent Articles

Automating with PowerShell: making stolen tokens useless with Global Secure Access

Last week I watched Merill Fernando talk to Alex Pavlovsky and Marilee Tuscak from the Entra team about something I’d kinda put under the “needs a GSA licence” branch and i’d check it out later, turns out that like most people, I half-assed the documentation and it turns out it doesn’t. There’s two features that come with any P1 license; Compliant network check and Source IP Restoration. So BP, P1, or even frontline worker licenses already have this.

CIPP ❤️ #IntuneForMSPs

We’re Joining #IntuneForMSPs 🎉

Being invited by Microsoft to join a global initiative is a big moment for us, and we want to be clear about why it matters. #IntuneForMSPs is Microsoft’s program to help MSPs deliver Microsoft 365, Intune, and Copilot services at scale, and CIPP is now part of it, bringing the largest MSP community in the channel directly to Microsoft.

The return of CyberDrain CTF

CyberDrain CTF returns! (and so do I!)

It’s been since september that I actually picked up a digital pen equivalent and wrote anything down. This was due to me being busy with life but also my side projects like CIPP. I’m trying to get back into the game of scripting and blogging about these scripts. There’s still so much to automate and so little time, right? ;)