unixpipe
unixpipe

Reputation: 75

Append to array in powershell job

I was able to find a piece of code that could ping all systems at once, better than any other job examples I've come across. This thing can take an entire file full of hosts, line by line, and ping them all literally at the same time. But how can I add the ones that are up to my $online array? I tried adding in the true block but it didn't work. Im simply trying to stick $online += $pc somewhere. Any help would be appreciated. Thanks.

$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 }}} | ft -AutoSize

Upvotes: 0

Views: 178

Answers (2)

Santiago Squarzon
Santiago Squarzon

Reputation: 60085

You can store the result of your jobs and then filter by Reachable. I've also simplified your code a bit and added -AutoRemove which I consider important to dispose your jobs when done.

$result = Get-Content C:\servers.txt | ForEach-Object {
    Test-Connection -ComputerName $_ -Count 1 -AsJob
} | Receive-Job -Wait -AutoRemoveJob | ForEach-Object {
    [pscustomobject]@{
        ComputerName = $_.Address
        Reachable    = $_.StatusCode -eq 0
    }
}

$online = $result | Where-Object Reachable

# if you want just the `ComputerName` values, you can do
$online = $result | Where-Object Reachable | ForEach-Object ComputerName

# or easier, using member-access enumeration and `.Where` method
$online = $result.Where{ $_.Reachable }.ComputerName

If you're interested in grouping the results between Reachable and Not Reachable during enumeration, the way to do it is with a hash table having 2 List<T> values.

$result = @{
    Online  = [System.Collections.Generic.List[object]]::new()
    Offline = [System.Collections.Generic.List[object]]::new()
}

Get-Content C:\servers.txt | ForEach-Object {
    Test-Connection -ComputerName $_ -Count 1 -AsJob
} | Receive-Job -Wait -AutoRemoveJob | ForEach-Object {
    $obj = [pscustomobject]@{
        ComputerName = $_.Address
        Reachable    = $_.StatusCode -eq 0
    }

    if($obj.Reachable) {
        return $result['Online'].Add($obj)
    }
    
    $result['Offline'].Add($obj)
}

$result.Online.ComputerName # => has all reachable records

Upvotes: 1

Minkulai
Minkulai

Reputation: 124

I believe the issue here is the pipe ft -autosize.

Try to pipe after the if/else statement as per below:

| ForEach-Object {
    if ($_.Reachable -eq $true) {
        $online += $_.ComputerName
    }
}

Then if you want to view the results you can always do:

$online | ft -AutoSize

I'd also suggest a better formatting as all one line isn't easy to read. Try something like this:

$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

Upvotes: 0

Related Questions