0

I'm having trouble getting background threads to work in Powershell. I'd like to use runspaces where I can plug a script into it and get updates when there is one and allow my main thread to do with that data what it needs to. I'm not sure why doesn't this code return the proper values? All of the servers I tested against return true when not used in a runspace, but the return value here is 0.

I'm not interested in using powershell jobs.

$servers = @("x1","x2","x3");
$results = New-Object Collections.Generic.List[String];
$input = New-Object 'System.Management.Automation.PSDataCollection[psobject]'
$output = New-Object 'System.Management.Automation.PSDataCollection[psobject]'
$results.Clear();
foreach ($server in $servers)
{
    Write-Host $server;
    $powerShell = [Management.Automation.PowerShell]::Create();
    [Void]$PowerShell.AddScript({
        $result = Test-Connection $server -Count 1 -Quiet; 
        return ($server - $result)
    })

    $handle = $powerShell.BeginInvoke($input,$output);
    $results.Add($output);
}

$results;

or

$results = New-Object Collections.Generic.List[String];
$input = New-Object 'System.Management.Automation.PSDataCollection[psobject]'
$output = New-Object 'System.Management.Automation.PSDataCollection[psobject]'
$results.Clear();
foreach ($server in $servers)
{
    Write-Host $server;
    $powerShell = [Management.Automation.PowerShell]::Create();
    [Void]$PowerShell.AddScript({
        param ($server)
        $result = Test-Connection $server -Count 1 -Quiet; 
        return ($server - $result)
    })

    $handle = $powerShell.BeginInvoke($server,$output);
    #$handle = $powerShell.BeginInvoke($input,$output);
    $results.Add($output);
}

$results;
Bbb
  • 517
  • 6
  • 27
  • 1
    Did you take a look at [jobs](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_jobs?view=powershell-6). These are designed to run tasks in the background. – boxdog May 22 '19 at 11:20
  • Yes, I'm not interested in using jobs – Bbb May 22 '19 at 11:34

1 Answers1

0

Have fun.

$servers = @("x1","x2","x3");
$input   = New-Object 'System.Management.Automation.PSDataCollection[psobject]'
$output  = New-Object 'System.Management.Automation.PSDataCollection[psobject]'

$GH = [hashtable]::Synchronized(@{})

[System.Collections.Generic.List[PSObject]]$GH.results = @()
[System.Collections.Generic.List[PSObject]]$jobs = @()

$initialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()

$runspacePool = [RunspaceFactory]::CreateRunspacePool(1, ([int]$env:NUMBER_OF_PROCESSORS + 1), $initialSessionState, $host )
$runspacePool.ApartmentState = 'MTA'
$runspacePool.ThreadOptions  = "ReuseThread"
[void]$runspacePool.Open()

$jobCounter = 1

foreach ($server in $servers)
{
    Write-Host $server;

    $job = [System.Management.Automation.PowerShell]::Create($initialSessionState)
    $job.RunspacePool = $runspacePool

    $scriptBlock = { param ( [hashtable]$GH, [string]$server ); $result = Test-Connection $server -Count 1 -Quiet; $GH.results.Add( [PSObject]@{ 'Server' = $server; 'Result' = $result } ) }

    [void]$job.AddScript( $scriptBlock ).AddArgument( $GH ).AddArgument( $server )
    $jobs += New-Object PSObject -Property @{
                                    RunNum = $jobCounter++
                                    JobObj = $job
                                    Result = $job.BeginInvoke() }

    do {
        Sleep -Seconds 1 
    } while( $runspacePool.GetAvailableRunspaces() -lt 1 )

}

Do {
    Sleep -Seconds 1
} While( $jobs.Result.IsCompleted -contains $false)


$GH.results;


$runspaces = Get-Runspace | Where { $_.Id -gt 1 }

foreach( $runspace in $runspaces ) {
    try{
        [void]$runspace.Close()
        [void]$runspace.Dispose()
    }
    catch {
    }
}

[void]$runspacePool.Close()
[void]$runspacePool.Dispose()
f6a4
  • 1,684
  • 1
  • 10
  • 13