Actually, after fiddling around with it for a bit, it turns out that Get-ConnectionInformation does help us, just not as one would expect. The existing EXO connection is readily available inside the threads; the only thing missing is the proxied Cmdlets from Exchange Online (i.e. the ad-hoc module created and loaded when calling Connect-ExchangeOnline isn't loaded in the threads, and module autoloading is of no help here).
Good news is that Get-ConnectionInformation actually exposes the path to the ad-hoc module, which makes it possible to import it inside the threads and just reuse the existing connection.
A basic example / POC:
Connect-ExchangeOnline
'a'..'z' | ForEach-Object -Parallel {
# Check if we are connected
if ($null -eq (Get-ConnectionInformation)) {
Throw 'Connect to Exchange Online first'
}
# Check to see if the module is loaded
if (-not (Test-Path function:Get-Mailbox)) {
Write-Output 'Loading module'
Import-Module (Get-ConnectionInformation).ModuleName -WarningAction SilentlyContinue
}
Get-Mailbox -ResultSize 10 -Filter ('PrimarySmtpAddress -like "{0}*"' -f $_) -WarningAction SilentlyContinue | Select-Object -ExpandProperty PrimarySmtpAddress
}
So basically, we can reuse the existing connection by simply loading the module inside each of the threads.
On a side note, in this example we even could have skipped module loading altogether and used Get-EXOMailbox instead.