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'

Or…

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

Or…

[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:

$Ping

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

$Ping.ExecutionTime

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

$Ping.Online

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

$Ping.Results

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. .gist table { margin-bottom: 0; } This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters class Ping { # Property [array] $Results [array] $Online [array] $Offline $ExecutionTime $TotalComputers $OnlineCount $OnlinePercent $OfflineCount $OfflinePercent # Constructor Ping ([array] $Computers) { function Invoke-MultiThreadedCommand { [CmdletBinding()] param( [parameter(Mandatory = $True,ValueFromPipeline = $True,Position = 0)] $ProcessArray, [parameter(Mandatory = $True)] [ScriptBlock]$Scriptblock, [parameter()] $ThrottleLimit = 32, [parameter()] [switch] $ShowProgress ) Begin { # Create runspacepool, add code and parameters and invoke Powershell [void][runspacefactory]::CreateRunspacePool() $SessionState = [Management.Automation.Runspaces.InitialSessionState]::CreateDefault() $script:RunspacePool = [runspacefactory]::CreateRunspacePool(1,$ThrottleLimit,$SessionState,$host) $RunspacePool.Open() # Function to start a runspace job function Start-RSJob { param( [parameter(Mandatory = $True,Position = 0)] [ScriptBlock]$Code, [parameter()] $Arguments ) if ($RunspacePool.GetAvailableRunspaces() -eq 0) { do { } Until ($RunspacePool.GetAvailableRunspaces() -ge 1) } $PowerShell = [powershell]::Create() $PowerShell.runspacepool = $RunspacePool [void]$PowerShell.AddScript($Code) foreach ($Argument in $Arguments) { [void]$PowerShell.AddArgument($Argument) } $job = $PowerShell.BeginInvoke() # Add the job and PS instance to the arraylist $temp = '' | Select-Object –Property PowerShell, Job $temp.PowerShell = $PowerShell $temp.Job = $job [void]$Runspaces.Add($temp) } # Start a 'timer' $Start = Get-Date # Define an arraylist to add the runspaces to $script:Runspaces = New-Object –TypeName System.Collections.ArrayList $i = 0 } Process { # 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 $_ } } } End { # 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)) %" } do { } 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 { $_.powershell.EndInvoke($_.Job) $_.PowerShell.Dispose() } $Runspaces.clear() [void]$RunspacePool.Close() [void]$RunspacePool.Dispose # 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 $return } } # Define the "Test-Connection" code $Code = { param($ComputerName) $RetryCount = 5 1..$RetryCount | ForEach-Object –Process { $Params = @{ ComputerName = $ComputerName BufferSize = 1 Count = 1 ErrorAction = 'SilentlyContinue' } $t = Test-Connection @Params if($t -eq $True) { Break } } if($t) { $t } } $Start = Get-Date $Result = $Computers | Invoke-MultiThreadedCommand –Scriptblock $Code –ShowProgress –ThrottleLimit 128 $End = Get-Date $On = $Result.ForEach{ $_.Address } $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*' }).DNSHostName 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 Ping.ps1 hosted with ❤ by GitHub

Leave a Reply to H-MAN 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 )

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.