Search code examples
powershellvariablesscopejobs

Use and modify my variable in all startthreadjob powershell


I need help because I'm having trouble using my variables in powershell jobs.

Let me explain

I want to create a counter to retrieve the number of ping OK

foreach($computer in $computers)
{
    Start-ThreadJob -ThrottleLimit 100 -ScriptBlock {
        if (Test-Connection $using:computer -count 1 -TimeoutSeconds 2 -Quiet)
        {
            $test_con = $test_con+1
        }
    }
}

write-host $test-con

I have no problem getting the $computer variable in start threadjob using the $using scope. But I can't increment the test_con variable each time test-connection is true, to get at the end the number of machines that ping.

I want to increment my global variable 'test_con' from jobs

I am using powershell 7, I never asked myself the question under bash linux

Could someone kindly explain to me how it works with powershell ?


Solution

  • You can indeed use the using scope modifier to resolve variable references in the calling scope, you just need a variable with a thread-safe collection type to write to:

    # Create a hashtable
    $counterTable = @{}
    
    # Make it thread-safe
    $counterTable = [hashtable]::Synchronized($counterTable)
    
    
    foreach($computer in $computers) {
        Start-ThreadJob -ThrottleLimit 100 -ScriptBlock {
            if (Test-Connection $using:computer -count 1 -TimeoutSeconds 2 -Quiet)
            {
                $counter = $using:counterTable
                $counter['ping'] += 1
            }
        }
    }
    
    Write-Host "We had $($counterTable['ping']) successful pings!"
    

    I'd personally prefer knowing which computers we could ping successfully, so I'd suggest storing the Test-Connection results in separate entries in the table instead:

    # Create a hashtable
    $pingTable = @{}
    
    # Make it thread-safe
    $pingTable = [hashtable]::Synchronized($pingTable)
    
    foreach($computer in $computers) {
        Start-ThreadJob -ThrottleLimit 100 -ScriptBlock {
            $pingTable = $using:pingTable
            $computerName = $using:computer
        
            $pingTable[$computerName] = Test-Connection $using:computer -Count 1 -TimeoutSeconds 2 -Quiet
        }
    }
    
    Write-Host "We had $($pingTable.psbase.Values.Where({!$_}).Count) failures!"
    $pingTable.GetEnumerator() |Sort Name |Format-Table |Out-Host