Search code examples
multithreadingpowershellexchange-serverrunspaceposhrsjob

Exchange Online Session and Runspace


I need to execute Get-MailboxStatistics in a Runspace. I can connect to Exchange online. If I do a 'Get-Pssession' I can see the Exchange session. But how do I pass this ExchangeOnline session to the Runspace to execute Get-MailboxStatistics. Currently it does not recognize the Get-MailboxStatistics command in the Runspace.

Here is my code (this is part of a larger script):

# Connecting to Exchange Online
$AdminName = "hil119"
$Pass = "password"
$cred_cloud = new-object -typename System.Management.Automation.PSCredential -argumentlist $AdminName, $Pass
Connect-ExchangeOnline -Credential $cred_cloud -Prefix Cloud

# Executing Get-MailboxStatistics in a Runspace
$Runspace = [runspacefactory]::CreateRunspace()
$PowerShell = [powershell]::Create()
$PowerShell.runspace = $Runspace
$Runspace.Open()
[void]$PowerShell.AddScript({Get-MailboxStatistics 'd94589'})
$PowerShell.BeginInvoke()

Solution

  • After days of research I found that you can run a thread on a local system or on a remote Exchange server. If you run it on the local system, then each thread needs to call the Exchange session on their own, but if you run it a remote exchange system (onprem or cloud) you can get the exchange session just once and pass that session to the thread. You can get a remote session with an Invoke command. Also I ended up writing the script in Poshjobs instead or runspaces. Ultimately from what I have read Poshjobs is a combination of Start-job and runspaces.

    So here is the snippet of code that be used to run a Thread on a remote server. With this script you can pass the same exchange session to all threads.

    Function Func_ConnectCloud
    {
    $AdminName = "r43667"
    $AdminPassSecure = "pass"
    $Cred_Cloud = new-object -typename System.Management.Automation.PSCredential -argumentlist $AdminName, $AdminPassSecure
    Connect-ExchangeOnline -Credential $Cred_Cloud
    $CloudSession =  Get-PSSession | Where { $_.ComputerName -like "outlook.office365*"}
    Return $CloudSession
    }
    
    $script_Remote = 
        {
    param(
         $Alias,
         $CloudSession
         )
    
    Invoke-Command -session $CloudSession -ArgumentList $Alias  -ScriptBlock {param($Alias); Get-MailboxStatistics $Alias}
        }
    
    $CloudSession = Func_ConnectCloud
    $Alias = 'h672892'
    $Job1 = Start-RsJob -Name "job_$Alias" -ScriptBlock $ScriptRemote -ArgumentList $Alias, $CloudSession
    
    Receive-RsJob $Job1
    Remove-RsJob $Job1

    You can use this script to run threads onprem as well as cloud, although when run on a cloud server, Microsoft will only allow TWO threads. If you run more that TWO threads, your Exchange session is killed (This is different from Throttling) . So if you have a cloud environment, then its best to run your threads locally. Special reference to @postanote for his script at https://powershell.org/forums/topic/connecting-to-office-365-in-psjobs/