How to make Powershell 5.1 runspaces execute a scriptBlock?

109 views Asked by At

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.

0

There are 0 answers