How to Multithread PowerShell Ping Script

powershell ping multiple servers at once
powershell multithreading foreach
powershell workflow
run scripts in parallel powershell
powershell multithread loop
invoke-ping.
start-parallel - powershell
powershell test-connection list of computers

I recently finished a script to ping every computer/workstation on a list and output it in a nice format.

There are thousands of computers to ping on the next list so it would take a while to run normally. How might I be able to multithread this so the job can be completed within a reasonable time-frame?

workflow Ping
{
  param($computers)

    foreach -parallel ($computer in $computers)
    {
        $status = Test-Connection -ComputerName $computer -Count 1 -Quiet

        if (!$status)
            { Write-Output "Could not ping $computer" }
    }
}

$computers = @(
    "wd1600023",
    "sleipnir"
)

Ping $computers

Script Ping multiple servers simultaneously with PowerShell: Test , Ping hundreds of machines at a time using PowerShell using multithreading (​without the added overhead of additional powershell.exe  This script ping multiple IP addresses simultaneously by multithreading the ping instances. An ICMP packet will be sent every second except parameter switch -Flood is used. The number of concurrent ping instances - threads - is controlled by variable $Throttle and the default value is set to 100.

You could spawn multiple jobs or you could use a workflow and a Foreach -parallel loop.

Use PowerShell Workflow to Ping Computers in Parallel, Here's the keyboard, Niklas. The Test-Connection cmdlet is used to send ICMP echo request packets (“ping”) to one or more remote computers. Another option to multithread your script is to use a separate runspace. Runspaces are the enclosed area that the thread (s) running PowerShell operate within. While the runspace that is used with the PowerShell console is restricted to a single thread, you can use additional runspaces to allow for use of additional threads.

I found and used this script as a baseline for a similar function Ping-IPRange.

I have modified it from the original and included it below.

You could easily adapt this to take in a list of hostnames if that is what you are using.

Ping-IPRange.ps1

function Ping-IPRange 
{
    <#
    .SYNOPSIS
        Sends ICMP echo request packets to a range of IPv4 addresses between two given addresses.

    .DESCRIPTION
        This function lets you sends ICMP echo request packets ("pings") to 
        a range of IPv4 addresses using an asynchronous method.

        Therefore this technique is very fast but comes with a warning.
        Ping sweeping a large subnet or network with many switches may result in 
        a peak of broadcast traffic.
        Use the -Interval parameter to adjust the time between each ping request.
        For example, an interval of 60 milliseconds is suitable for wireless networks.
        The RawOutput parameter switches the output to an unformatted
        [System.Net.NetworkInformation.PingReply[]].

    .INPUTS
        None
        You cannot pipe input to this function.

    .OUTPUTS
        The function only returns output from successful pings.

        Type: System.Net.NetworkInformation.PingReply

        The RawOutput parameter switches the output to an unformatted
        [System.Net.NetworkInformation.PingReply[]].

    .NOTES
        Author  : G.A.F.F. Jakobs
        Created : August 30, 2014
        Version : 6

        Revision History: Kory Gill, 2016/01/09
            formatting
            added better error handling
            close progress indicator when complete

    .EXAMPLE
        Ping-IPRange -StartAddress 192.168.1.1 -EndAddress 192.168.1.254 -Interval 20

        IPAddress                                 Bytes                     Ttl           ResponseTime
        ---------                                 -----                     ---           ------------
        192.168.1.41                                 32                      64                    371
        192.168.1.57                                 32                     128                      0
        192.168.1.64                                 32                     128                      1
        192.168.1.63                                 32                      64                     88
        192.168.1.254                                32                      64                      0

        In this example all the ip addresses between 192.168.1.1 and 192.168.1.254 are pinged using 
        a 20 millisecond interval between each request.
        All the addresses that reply the ping request are listed.

    .LINK
        http://gallery.technet.microsoft.com/Fast-asynchronous-ping-IP-d0a5cf0e

    #>
    [CmdletBinding(ConfirmImpact='Low')]
    Param(
        [parameter(Mandatory = $true, Position = 0)]
        [System.Net.IPAddress]$StartAddress,
        [parameter(Mandatory = $true, Position = 1)]
        [System.Net.IPAddress]$EndAddress,
        [int]$Interval = 30,
        [Switch]$RawOutput = $false
    )

    $timeout = 2000

    function New-Range ($start, $end) {

        [byte[]]$BySt = $start.GetAddressBytes()
        [Array]::Reverse($BySt)
        [byte[]]$ByEn = $end.GetAddressBytes()
        [Array]::Reverse($ByEn)
        $i1 = [System.BitConverter]::ToUInt32($BySt,0)
        $i2 = [System.BitConverter]::ToUInt32($ByEn,0)
        for ($x = $i1;$x -le $i2;$x++)
        {
            $ip = ([System.Net.IPAddress]$x).GetAddressBytes()
            [Array]::Reverse($ip)
            [System.Net.IPAddress]::Parse($($ip -join '.'))
        }
    }

    $ipRange = New-Range $StartAddress $EndAddress

    $IpTotal = $ipRange.Count

    Get-Event -SourceIdentifier "ID-Ping*" | Remove-Event
    Get-EventSubscriber -SourceIdentifier "ID-Ping*" | Unregister-Event

    $ipRange | ForEach-Object {

        [string]$VarName = "Ping_" + $_.Address

        New-Variable -Name $VarName -Value (New-Object System.Net.NetworkInformation.Ping)

        Register-ObjectEvent -InputObject (Get-Variable $VarName -ValueOnly) -EventName PingCompleted -SourceIdentifier "ID-$VarName"

        (Get-Variable $VarName -ValueOnly).SendAsync($_,$timeout,$VarName)

        Remove-Variable $VarName

        try
        {

            $pending = (Get-Event -SourceIdentifier "ID-Ping*").Count

        } 
        catch [System.InvalidOperationException]
        {
            $pending = 0
        }

        $index = [array]::indexof($ipRange,$_)

        Write-Progress -Activity "Sending ping to" -Id 1 -status $_.IPAddressToString -PercentComplete (($index / $IpTotal)  * 100)

        $percentComplete = ($($index - $pending), 0 | Measure-Object -Maximum).Maximum

        Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($index - $pending) -PercentComplete ($percentComplete/$IpTotal * 100)

        Start-Sleep -Milliseconds $Interval
    }

    Write-Progress -Activity "Done sending ping requests" -Id 1 -Status 'Waiting' -PercentComplete 100 

    while ($pending -lt $IpTotal) {

        Wait-Event -SourceIdentifier "ID-Ping*" | Out-Null

        Start-Sleep -Milliseconds 10

        try
        {

            $pending = (Get-Event -SourceIdentifier "ID-Ping*").Count

        }
        catch [System.InvalidOperationException]
        {
            $pending = 0
        }

        $percentComplete = ($($IpTotal - $pending), 0 | Measure-Object -Maximum).Maximum

        Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($IpTotal - $pending) -PercentComplete ($percentComplete/$IpTotal * 100)
    }

    Write-Progress -Completed -Id 2 -ParentId 1 -Activity "Completed"
    Write-Progress -Completed -Id 1 -Activity "Completed"

     $Reply = @()

    if ($RawOutput)
    {
        Get-Event -SourceIdentifier "ID-Ping*" | ForEach { 
            if ($_.SourceEventArgs.Reply.Status -eq "Success")
            {
                $Reply += $_.SourceEventArgs.Reply
            }
            Unregister-Event $_.SourceIdentifier
            Remove-Event $_.SourceIdentifier
        }
    }
    else
    {
        Get-Event -SourceIdentifier "ID-Ping*" | ForEach-Object { 
            if ($_.SourceEventArgs.Reply.Status -eq "Success")
            {
                $pinger = @{
                    IPAddress = $_.SourceEventArgs.Reply.Address
                    Bytes = $_.SourceEventArgs.Reply.Buffer.Length
                    Ttl = $_.SourceEventArgs.Reply.Options.Ttl
                    ResponseTime = $_.SourceEventArgs.Reply.RoundtripTime
                }
                $Reply += New-Object PSObject -Property $pinger
            }
            Unregister-Event $_.SourceIdentifier
            Remove-Event $_.SourceIdentifier
        }
    }

    if ($Reply.Count -eq 0)
    {
        Write-Verbose "Ping-IPRange : No IP address responded" -Verbose
    }

    return $Reply
}

Pinging an IP address - Biamp Systems, FrameWork). It brings a cool set of functionalities such as the possibilities to execute code in parallel, to create scripts that are persist to reboot, and lot's of other neat things. PowerShell-MultiThread-Ping #Prompting the user to enter a text file path where a list of computers are located $computerFile = Read-Host "Enter the path to a text file where the list of comptuers is located. i.e. c:\temp\computer.txt" #Grabbing a list of computer names from a text file

Scripting How To: Ping Multiple Servers and Export Results , #This script block stores a list of commands that you want to perform. This is not just limited to a simple ping that I am demonstrating. $scriptBlock = {. #parameter​  We can use multi threading in powershell v2 using start-job command which will execute the script block on multiple servers parallely rather than going one by one. In powershell v3 there is additional option to execute command parallel within foreach loop itself Foreach -parallel ($srv in gc c:\input.txt)

PowerShell workflow: everything you ever needed to know about it! -, This works great, but what if you wanted to ping many systems at a time to figure out their availability? to provide some multithreading to attempt to ping more than one system at a time. 2013 Powershell Scripting Games  Record everything that occurs in your powershell prompt, Never lose any of that work ever again! PS> Start-Transcript -path C:/Script/PingLog.txt -Append I think this is pretty self explanatory, The Append flag is telling it to continue on if the file already exists, this isn't necessary, and depends on how you would like to name/use the file.

PowerShell-MultiThread-Ping · GitHub, * It uses significantly less memory, because Start-Job starts a completely new, fully blown Powershell process, including the respective conhost. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.