I am writing a test code for runspaces for a future project. When I run the code the runspaces are properly created and "completed", however they never actually execute the scriptBlock denoted in $codeContainer.
EDIT TO INCLUDE LOG PATH
$VerbosePreference = "Continue"
$LogPath = Join-Path -Path (Split-Path $MyInvocation.MyCommand.Path) -ChildPath "Script Logs"
If (-not (Test-Path $LogPath))
{
New-Item $LogPath -ItemType Directory | Out-Null
}
Get-ChildItem "$LogPath\*.log" | Where LastWriteTime -LT (Get-Date).AddDays(-7) | Remove-Item -Confirm:$false
$LogPathName = Join-Path -Path $LogPath -ChildPath "$($MyInvocation.MyCommand.Name)-$(Get-Date -Format 'MM-dd-yyyy').log"
Start-Transcript $LogPathName -Append
$runspacePool = [RunspaceFactory]::CreateRunspacePool(1, 5) # 1 = minimum num threads running at once usually 1,
# 4 = max threads running at once, last thing you should tune, start testing with 2-4
$runspacePool.ApartmentState = "MTA" # String should be "Unknown", "None", "MTA", or "STA", for our purposes we will only ever need "MTA"
# If we are worried about the order the threads complete set to "STA"
$runspacePool.Open() # Initializes runspacePool
#############################################################################################################################################################
$codeContainer = {
Param([String] $clientName)
# Replace this line with your custom code
Write-Host "Processing client: $clientName"
}
$threads = @() # Initializes an empty array to contain objects for the threads to run
$StopWatch = [System.Diagnostics.Stopwatch]::new() # Tracks speed of below processes
$Stopwatch.Start()
ForEach($clientName in $clientList) {
$runspaceObject = [PSCustomObject] @{
Runspace = [PowerShell]::Create() # Contains runspace of the running thread
Invoker = $null # Stores the status of the thread (complete/incomplete)
}
$runspaceObject.Runspace.AddScript($codeContainer) | Out-Null # Adds the script block to the runspace
$runspaceObject.Runspace.AddParameter($clientName) | Out-Null # Tells runspace on what server to run the script
$runspaceObject.Invoker = $runspaceObject.Runspace.BeginInvoke() # Sets the Invoker to Thread Status Complete object or Thread Status Incomplete object
$threads += $runspaceObject # Adds the custom object to the threads
$elapsed = $StopWatch.Elapsed # Captures time taken to start up a thread
Write-Host "Finished creating runspace for $clientName. Elapsed Time: $elapsed"
}
##############################################################################################################################################################
$elapsed = $StopWatch.Elapsed # Captures time taken to start up all threads
Write-Host "Finished creating all runspaces. Elapsed Time: $elapsed"
While ($threads.Invoker.IsCompleted -contains $false -or $threads.Invoker.IsCompleted -eq $null) {
# Empty block to ensure all threads have completed
}
$elapsed = $StopWatch.Elapsed
Write-Host "All runspaces completed. Elapsed Time: $elapsed"
$threadResults = @() # Empty list to store results of threads
ForEach ($t in $threads) {
$threadResults += $t.Runspace.EndInvoke($t.Invoker) # Pull results if thread is complete and store in threadResults
$t.Runspace.Dispose() # Dispose of the thread when completed
}
$StopWatch.Stop()
$runspacePool.Close() # Close the runspace pool
$runspacePool.Dispose() # Dispose of the runspace pool
I have tried many solutions, however none seem to work. I think it has to either do with an improper scope, or an improper implementation of AddScript. I'm not sure which however. $clientList is defined above the included code as a list of strings, everything above the included code works as expected, and is simply just a form to get the clientList.