Public/Fast-Ping.ps1
|
Function Fast-Ping { <# .DESCRIPTION Super fast ping results for large quantities of hosts. .EXAMPLE Fast-Ping "myserver.domain.com","yourserver.domain.com" .EXAMPLE Get-Content C:\test\RandomHosts.txt | Select-Object -First 100 | Fast-Ping .NOTES Author: Tyson Paul Original Author: unknown Original script: https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/final-super-fast-ping-command I modifed this a bit. I added the ability to determine the max number of hostnames to process without choking the Get-WmiObject cmdlet, then recursively probe the chunks of the input hosts array. #> param ( # make parameter pipeline-aware [Parameter(Mandatory,ValueFromPipeline)] # one or more computer names (array) [string[]]$ComputerName, $TimeoutMillisec = 4000 ) begin { [int]$maxParam = 16384 # use this to collect computer names that were sent via pipeline [Collections.ArrayList]$bucket = @() # hash table with error code to text translation $StatusCode_ReturnValue = @{ 0 = 'Success' 11001 = 'Buffer Too Small' 11002 = 'Destination Net Unreachable' 11003 = 'Destination Host Unreachable' 11004 = 'Destination Protocol Unreachable' 11005 = 'Destination Port Unreachable' 11006 = 'No Resources' 11007 = 'Bad Option' 11008 = 'Hardware Error' 11009 = 'Packet Too Big' 11010 = 'Request Timed Out' 11011 = 'Bad Request' 11012 = 'Bad Route' 11013 = 'TimeToLive Expired Transit' 11014 = 'TimeToLive Expired Reassembly' 11015 = 'Parameter Problem' 11016 = 'Source Quench' 11017 = 'Option Too Big' 11018 = 'Bad Destination' 11032 = 'Negotiating IPSEC' 11050 = 'General Failure' } # hash table with calculated property that translates # numeric return value into friendly text $statusFriendlyText = @{ Name = 'Status' Expression = { # take status code and use it as index into # the hash table with friendly names # make sure the key is of same data type (int) $StatusCode_ReturnValue[([int]$_.StatusCode)] } } # calculated property that returns $true when status -eq 0 $IsOnline = @{ Name = 'Online' Expression = { $_.StatusCode -eq 0 } } # do DNS resolution when system responds to ping $DNSName = @{ Name = 'DNSName' Expression = { if ($_.StatusCode -eq 0) { if ($_.Address -like '*.*.*.*') { [Net.DNS]::GetHostByAddress($_.Address).HostName } else { [Net.DNS]::GetHostByName($_.Address).HostName } } } } } process { # add each computer name to the bucket # we either receive a string array via parameter, or # the process block runs multiple times when computer # names are piped $ComputerName | ForEach-Object -Process { $name = $_ -replace ' ','' $null = $bucket.Add($name) } } end { # Recursively break down query strings that are too long. # Assemble the query with all addresses $query = $bucket -join "' or Address='" If ($query.length -gt $maxParam) { $tmpQuery = $query.Clone() $div = 1 # If the query is too large, figure out what size chunk of the addresses will be under threshold/max size While ($tmpQuery.Length -gt $maxParam) { $div++ $tmpQuery = $bucket[0..([math]::Floor(($bucket.Count / $div)))] -join "' or Address='" } # This size chunk of addresses should be small enough, acceptable as a parameter. $start = [math]::Floor(($bucket.Count / $div)) Write-Verbose -Message "Starting size: $start" $index = 0 For($i = $start; $i -le ($bucket.Count -1); $i = ([math]::Min(($i + $start),($bucket.Count -1))) ) { Write-Verbose -Message "Range:$($index)-$($i)" $Result += Fast-Ping -ComputerName $bucket[($index)..$i] -TimeoutMillisec $TimeoutMillisec If ($i -eq ($bucket.Count -1)) { break } $index = $i+1 } } Else { $Result += Get-WmiObject -Class Win32_PingStatus -Filter "(Address='$query') and timeout=$TimeoutMillisec" | Select-Object -Property Address, $DNSName, $IsOnline, $statusFriendlyText } Return $Result } } |