Search code examples
powershelloffice365powershell-remoting

Looping through Exchange Online clients in PowerShell. Faster way to do this?


I'm sure this is a pretty normal scenario, but I have a few situations where I need to loop through my clients and connect to their Exchange Online infrastructure via PowerShell. Currently, I do this:

# Specifying credentials and connecting to Office 365 module
$Credential = Get-Credential

Connect-MsolService -Credential $Credential

# Getting a list of tenant IDs (clients) used to connect to their environment
$Tenants = (Get-MsolPartnerContract).TenantID.Guid


# Running command against all tenants
ForEach ($Tenant in $Tenants) {
    # Get primary domain for the tenant
    $Domain = (Get-MsolDomain -TenantId $Tenant `
            | Where-Object { `
                $_.Name -NotLike "*onmicrosoft.com" -and `
                $_.Name -NotLike "*microsoftonline.com" })[0].Name

    # Authenticating to Exchange Online for the tenant
    $Session = New-PSSession `
        -ConfigurationName Microsoft.Exchange `
        -ConnectionUri https://outlook.office365.com/powershell-liveid?DelegatedOrg=$Domain `
        -Credential $Credential `
        -Authentication Basic `
        -AllowRedirection

    Import-PSSession $Session -ErrorAction 'silentlycontinue'

    # Logic goes here...

    Remove-PSSession $Session
}

This may have been something I just missed in the docs, but is there a faster way to run commands against multiple sessions? Currently, it's taking a long time to just connect, which of course adds up when connecting to a lot of different tenants.


Solution

  • Use Start-Job

    I won't write full code here, but you might want to try creating different Jobs for each client/connection. See Start-Job and similar cmdlets. The aim would be to spin a number of these in parallel and wait for them to finish.

    For each of your tenants you can start a job and keep track of the Job object that is created, e.g.

    $jobs = @{}
    
    # create the jobs
    foreach($tenant in $tenants) {
       $jobs[$tenant] = Start-Job ...
    }
    

    Once you have started the jobs, find a way to wait for them to finish and collect any output the code may have spat out.