Power Ping

This custom class for PowerShell 5 and better allows you to “ping” multiple machines very quickly and easily using a parallel processing technique.  The object you create with this class contains various results such as:

  • The full “Test-Connection” results
  • The list of online machines
  • The list of offline machines
  • The count and percentage of online and offline machines
  • The execution time of the command

The class uses the “Test-Connection” cmdlet (which uses a WMI Win32_PingStatus method by the way), so the full results returned by this cmdlet can be viewed.  .Net runspaces are used to create a parallel processing environment to ensure quick results.

captureDownload the Class

Download from GitHub.  Run the code in your session to make the class available, or follow the instructions in my post on creating a class library to automatically import custom classes into your session.

Using the Class

The easiest way to use the class is to create a custom object of this type.  You must pass an array of computer names which you can import from a csv file, or simply type out an array of computers, for example:

[ping]$Ping = 'PC001','PC002','PC003'


[ping]$Ping = Get-Content C:\temp\computerstoping.csv


[ping]$Ping = $Computers

After you hit enter, the code will run and ping the machines in the list in parallel.

To return all the properties of the object, simply type the variable name as in the screenshot above:


To access any individual property of the object, simply use the dot operator:


To view the list of computers that are online and responded to the ping, view the “online” property:


To view the full results for those machines that responded to ping, view the “results” property:


To view the full list of properties returned for an individual machine, you can use the index number, or a where method for example.

$Ping.Results[1] | Select *
$Ping.Results.Where{$_.Address -eq "PC001"} | Select *

You can also create a new instance of the class type without storing it in memory as a variable, for example if you just wanted to see which computers were online from a list, you can do this:

[ping]::new($(Get-content C:\temp\computers.csv)).Online

The parallel processing uses a session limit of 64, but you can change this in the class code towards the end.

5 thoughts on “Power Ping

  1. Awesome class it simplifies things quite a bit,I created a similar script which was multi threaded but without a class, I added a retry if the host if down on the first attempt.

    class Ping
    # Property
    [array] $Results
    [array] $Online
    [array] $Offline
    # Constructor
    Ping ([array] $Computers)
    function Invoke-MultiThreadedCommand
    [parameter(Mandatory = $True,ValueFromPipeline = $True,Position = 0)]
    [parameter(Mandatory = $True)]
    $ThrottleLimit = 32,
    # Create runspacepool, add code and parameters and invoke Powershell
    $SessionState = [Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
    $script:RunspacePool = [runspacefactory]::CreateRunspacePool(1,$ThrottleLimit,$SessionState,$host)
    # Function to start a runspace job
    function Start-RSJob
    [parameter(Mandatory = $True,Position = 0)]
    if ($RunspacePool.GetAvailableRunspaces() -eq 0)
    Until ($RunspacePool.GetAvailableRunspaces() -ge 1)
    $PowerShell = [powershell]::Create()
    $PowerShell.runspacepool = $RunspacePool
    foreach ($Argument in $Arguments)
    $job = $PowerShell.BeginInvoke()
    # Add the job and PS instance to the arraylist
    $temp = '' | Select-Object Property PowerShell, Job
    $temp.PowerShell = $PowerShell
    $temp.Job = $job
    # Start a 'timer'
    $Start = Get-Date
    # Define an arraylist to add the runspaces to
    $script:Runspaces = New-Object TypeName System.Collections.ArrayList
    $i = 0
    # Start an RS job for each computer
    $ProcessArray | ForEach-Object Process {
    if ($PSCmdlet.MyInvocation.BoundParameters['Verbose'].IsPresent)
    $host.UI.WriteVerboseLine("Starting RS job for $_")
    Start-RSJob Code $Scriptblock Arguments $_
    $i ++
    if ($ShowProgress)
    Write-Progress Activity 'Invoking Jobs' CurrentOperation $_
    # Wait for each script to complete
    if ($PSCmdlet.MyInvocation.BoundParameters['Verbose'].IsPresent)
    $host.UI.WriteVerboseLine('Waiting for RS jobs to finish')
    $x = 0
    foreach ($item in $Runspaces)
    $x ++
    if ($ShowProgress)
    Write-Progress Activity 'Retrieving Job Output' PercentComplete ($x / $i * 100) Status "$([math]::Round(($x / $i * 100),0)) %"
    until ($item.Job.IsCompleted -eq 'True')
    # Grab the output from each script, and dispose the runspaces
    if ($PSCmdlet.MyInvocation.BoundParameters['Verbose'].IsPresent)
    $host.UI.WriteVerboseLine('Retrieving results and disposing runspaces')
    $return = $Runspaces | ForEach-Object Process {
    # Stop the 'timer'
    $End = Get-Date
    $TimeTaken = [math]::Round(($End $Start).TotalSeconds,2)
    if ($PSCmdlet.MyInvocation.BoundParameters['Verbose'].IsPresent)
    $host.UI.WriteVerboseLine("Command completed in $TimeTaken seconds")
    # Return the results
    # Define the "Test-Connection" code
    $Code = {
    $RetryCount = 5
    1..$RetryCount | ForEach-Object Process {
    $Params = @{
    ComputerName = $ComputerName
    BufferSize = 1
    Count = 1
    ErrorAction = 'SilentlyContinue'
    $t = Test-Connection @Params
    if($t -eq $True)
    $Start = Get-Date
    $Result = $Computers | Invoke-MultiThreadedCommand Scriptblock $Code ShowProgress ThrottleLimit 128
    $End = Get-Date
    $On = $Result.ForEach{
    $Off = $Computers.Where{
    $_ -notin $On
    $this.Results = $Result
    $this.Online = $On
    $this.Offline = $Off
    $this.ExecutionTime = "$([math]::Round(($End $Start).TotalSeconds,2)) seconds"
    $this.OfflineCount = $Off.Count
    $this.OnlineCount = $On.Count
    $this.TotalComputers = $Computers.Count
    $this.OnlinePercent = "$([math]::Round(($($On.Count) / $($Computers.Count) * 100))) %"
    $this.OfflinePercent = "$([math]::Round(($($Off.Count) / $($Computers.Count) * 100))) %"
    [ping]$Results = (Get-ADComputer Filter {
    OperatingSystem -like '*Windows Server*'
    Write-Host "TotalComputers: $($Results.TotalComputers)"
    Write-Host "OnlineCount: $($Results.OnlineCount)"
    Write-Host "OnlinePercent: $($Results.OnlinePercent)"
    Write-Host "OfflineCount: $($Results.OfflineCount)"
    Write-Host "OfflinePercent: $($Results.OfflinePercent)"
    Write-Host "ExecutionTime: $($Results.ExecutionTime)"
    Write-Host ' '
    Foreach ($Result in $($Results.Offline))
    Write-Host "Host $Result is offline"

    view raw
    hosted with ❤ by GitHub

Leave a Reply to Trevor Jones Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.