powershellscriptingjobsrunspace

Test-NetConnection -AsJob?


Is there any way I can utilize this piece of code with Test-NetConnection -ComputerName $_ -Port 5985 instead of Test-Connection -ComputerName $_ -Count 1 -AsJob ? I can't utilize -AsJob with the Test-NetConnection cmdlet. Are there any workarounds?

Here is my code:

$online = @()
$pc = Get-Content C:\servers.txt 
$pc | ForEach-Object { 
    Test-Connection -ComputerName $_ -Count 1 -AsJob 
} | Get-Job | Receive-Job -Wait | 
Select-Object @{Name='ComputerName';Expression={$_.Address}},@{Name='Reachable';Expression={
    if ($_.StatusCode -eq 0) { 
        $true 
    } else { 
        $false 
    }
}} | ForEach-Object {
    if ($_.Reachable -eq $true) {
        $online += $_.ComputerName
    }
}
$online | ft -AutoSize

servers.txt just basically has hostnames of all the machines on the network.


Solution

  • With vanilla Windows PowerShell 5.1 the best you can get is using a RunspacePool, the code is not easy to follow and for a good reason there are many modules available to handle multithreading in PowerShell. The most recommended one would be ThreadJob.
    This answer offers a "copy-pastable" version of a function that can handle multithreading from pipeline similar to ForEach-Object -Parallel but compatible with Windows PowerShell 5.1.

    $ProgressPreference = 'Ignore'
    $maxThreads = 32 # How many jobs can run at the same time?
    
    $pool = [runspacefactory]::CreateRunspacePool(1, $maxThreads,
        [initialsessionstate]::CreateDefault2(), $Host)
    
    $pool.Open()
    
    $jobs = [System.Collections.Generic.List[hashtable]]::new()
    
    Get-Content C:\servers.txt | ForEach-Object {
        $instance = [powershell]::Create().AddScript({
            param($computer)
    
            [pscustomobject]@{
                Computer = $computer
                Port     = 5985
                PortOpen = Test-NetConnection $computer -Port 5985 -InformationLevel Quiet
            }
        }).AddParameters(@{ computer = $_ })
    
        $instance.RunspacePool = $pool
    
        $jobs.Add(@{
            Instance = $instance
            Async    = $instance.BeginInvoke()
        })
    }
    
    $result = while($jobs) {
        $job = $jobs[[System.Threading.WaitHandle]::WaitAny($jobs.Async.AsyncWaitHandle)]
        $job.Instance.EndInvoke($job.Async)
        $job.Instance.Dispose()
        $null = $jobs.Remove($job)
    }
    
    $pool.Dispose()
    
    $result | Where-Object PortOpen # filter only for computers with this port open