Functions/Test-ConnectionAsync.ps1

Function Test-ConnectionAsync {
<#
.SYNOPSIS
    Performs a ping test asynchronously
.DESCRIPTION
    Performs a ping test asynchronously
.PARAMETER Computername
    List of computers to test connection
.PARAMETER Timeout
    Timeout in milliseconds. Default 2000 ms.
.PARAMETER TimeToLive
    Sets a time to live on ping request.
.PARAMETER Fragment
    Tells whether to fragment the request
.PARAMETER BufferSize
    How large you want the buffer to be. Valid range 32-1500
.PARAMETER IncludeSource
    A switch determining if you want the source computer name to appear in the output
.NOTES
    Inspired by Test-ConnectionAsync by 'Boe Prox'
    https://gallery.technet.microsoft.com/scriptcenter/Asynchronous-Network-Ping-abdf01aa
    * fixed logic around processing pipeline
    * removed $Buffer parameter
    * added $BufferSize parameter and dynamically create $Buffer from $BufferSize
    * added $IncludeSource so that source computer would be included in output
.OUTPUTS
    Net.AsyncPingResult
.EXAMPLE
    Test-ConnectionAsync -Computername server1,server2
 
    Computername IPAddress BufferSize Result ResponseTime
    ------------ --------- ---------- ------ ------------
    server1 192.168.1.31 32 Success 86
    server2 192.168.1.41 32 Success 79
 
    Description
    -----------
    Performs asynchronous ping test against listed systems.
#>


    #Requires -Version 3.0

    [OutputType('Net.AsyncPingResult')]
    [CmdletBinding(ConfirmImpact='None')]
    Param (
        [parameter(ValueFromPipeline,Position=0)]
        [string[]] $Computername,

        [parameter()]
        [int32] $Timeout = 2000,

        [parameter()]
        [Alias('Ttl')]
        [int32] $TimeToLive = 128,

        [parameter()]
        [switch] $Fragment,

        [parameter()]
        [validaterange(32,1500)]
        [int16] $BufferSize = 32,

        [parameter()]
        [switch] $IncludeSource
    )

    begin {
        if ($IncludeSource) { $Source = $env:ComputerName }

        $Buffer = New-Object -TypeName System.Collections.ArrayList
        1..$BufferSize | foreach-object { $null = $Buffer.Add(([byte] [char] 'A')) }
        $PingOptions = New-Object -TypeName System.Net.NetworkInformation.PingOptions
        $PingOptions.Ttl = $TimeToLive
        If (-NOT $PSBoundParameters.ContainsKey('Fragment')) {
            $Fragment = $False
        }
        $PingOptions.DontFragment = $Fragment
        $Computerlist = New-Object -TypeName System.Collections.ArrayList
    }

    process {
        ForEach ($Computer in $Computername) {
            [void] $Computerlist.Add($Computer)
            }
    }

    end {
        $Task = foreach ($Computer in $ComputerList) {
            [pscustomobject] @{
                Computername = $Computer
                Task         = (New-Object -TypeName System.Net.NetworkInformation.Ping).SendPingAsync($Computer, $Timeout, $Buffer, $PingOptions)
            }
        }
        Try {
            [void][Threading.Tasks.Task]::WaitAll($Task.Task)
        } Catch {
            Write-Error -Message "Error checking [$Computer]"
        }
        $Task | ForEach-Object {
            If ($_.Task.IsFaulted) {
                $Result = $_.Task.Exception.InnerException.InnerException.Message
                $IPAddress = $Null
                $ResponseTime = $Null
            } Else {
                $Result = $_.Task.Result.Status
                $IPAddress = $_.task.Result.Address.ToString()
                $ResponseTime = $_.task.Result.RoundtripTime
            }
            if ($IncludeSource) {
                $Object = [pscustomobject] @{
                    Source       = $Source
                    Computername = $_.Computername
                    IPAddress    = $IPAddress
                    BufferSize   = $BufferSize
                    Result       = $Result
                    ResponseTime = $ResponseTime
                }
            } else {
                $Object = [pscustomobject]@{
                    Computername = $_.Computername
                    IPAddress    = $IPAddress
                    BufferSize   = $BufferSize
                    Result       = $Result
                    ResponseTime = $ResponseTime
                }
            }
            $Object.pstypenames.insert(0, 'Net.AsyncPingResult')
            $Object
        }
    }

}