public/Test-FastPing.ps1

<#
.SYNOPSIS
   Module for performing ping and TCP port check.
.DESCRIPTION
   Use this module to perform connection state scripting.
   Combine with the Start-Multithreading module to perform on large target sets.
.EXAMPLE
    Fast-Ping -ComputerName $cn -Port $prt

    Name : TEST-00
    Online : True
    A : Unable to resolve
    AAAA : Unable to resolve
    Port 445 Open : True
 .PARAMETER ComputerName
    This parameter is required and must be in the form of valid DNS name or IP address.

    $ComputerName = 'TEST-00'
 .PARAMETER Port
    This parameter is optional, though must be in the form of a valid TCP port.

    $Port = 445
 .PARAMETER Lookup
    This parameter is optional. If invoked, there are no values, it is a switch to true

    $Lookup = $false
.NOTES
    Project: https://github.com/tmknight/TMK-CoreModules
#>


Function Test-FastPing {
    [CmdletBinding(SupportsShouldProcess = $true)]
    Param(
        ## ComputerName, required.
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Position = 0)]
        [ValidateScript( {
                if ($_ -match '^\w' -or $_ -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') {
                    $true
                }
                else {
                    Throw [System.Management.Automation.ValidationMetadataException] 'Please only enter valid DNS name or IP address'
                    Start-Sleep -Seconds 60
                }
            } )]
        [string]$ComputerName,

        ## TCP port to knock, optional
        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Position = 1)]
        [int]$Port,

        ## Perform lookup
        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Position = 2)]
        [switch]$Lookup
    )

    Begin {
        $ErrorActionPreference = 'SilentlyContinue'

        ## Clear variables
        $vars = 'rslt'
        Remove-Variable $vars
    }
    Process {
        ## Test device availability
        Function fastping {
            [CmdletBinding()]
            [OutputType([System.Boolean])]
            Param(
                [String]$cn
            )

            ## Initialize ping object
            $ping = New-Object System.Net.NetworkInformation.Ping
            try {
                ## Attempt connection, 300 millisecond timeout, returns boolean
                switch ($ping.send($cn, 300).status) {
                    'Success' { Return $true }
                    Default {
                        ## Do one more should the first one fail
                        switch ($ping.send($cn, 300).status) {
                            'Success' { Return $true }
                            Default { Return $false }
                        }
                    }
                }
            }
            catch {
                ## Any failure returns false
                Return $false
            }
        }

        Function portKnock {
            [CmdletBinding()]
            [OutputType([System.Boolean])]
            param (
                [string]$cn,
                [int]$prt
            )

            ## Initialize object
            $connection = New-Object Net.Sockets.TcpClient
            try {
                ## Attempt connection, 300 millisecond timeout, returns boolean
                $open = ($connection.BeginConnect($cn, $prt, $Null, $Null)).AsyncWaitHandle.WaitOne(300)
            }
            catch {
                $open = $false
            }

            ## Cleanup
            $connection.Close()

            Return $open
        }

        Function lookup {
            [CmdletBinding()]
            [OutputType([System.Object[]])]
            Param(
                [string]$cn,
                [bool]$Lookup
            )

            if ($Lookup -eq $false) {
                $ipv4 = 'N/A'
                $ipv6 = 'N/A'
                $hName = 'N/A'
            }
            elseif ($dns = Resolve-DnsName -Name $cn) {
                ForEach ($rdn in $dns) {
                    if ($rdn.type -eq 'A') {
                        $ipv4 = $rdn.ipaddress
                    }
                    else {
                        $ipv4 = 'Unable to resolve'
                    }

                    if ($rdn.type -eq 'AAAA') {
                        $ipv6 = $rdn.ipaddress
                    }
                    else {
                        $ipv6 = 'Unable to resolve'
                    }

                    ## Reverse lookup when cn is an IP address
                    switch -Regex ($cn) {
                        ## IP Address
                        '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' {
                            $hName = $rdn.NameHost
                            $ipv4 = 'N/A'
                            $ipv6 = 'N/A'
                        }
                        ## Hostname
                        Default {
                            $hName = $cn
                        }
                    }
                }
            }
            else {
                $ipv4 = 'Unable to resolve'
                $ipv6 = 'Unable to resolve'
                $hName = 'Unable to resolve'
            }
            Return $ipv4, $ipv6, $hName
        }

        ## NS Lookup
        $lku = lookup -cn $ComputerName -Lookup $Lookup

        ## Results
        $rslt = [PSCustomObject] @{
            ComputerName  = $ComputerName
            HostName      = $lku[2]
            PingSucceeded = (fastping -cn $ComputerName)
            A             = $lku[0]
            AAAA          = $lku[1]
            # "Port $Port Open" = (portKnock -cn $ComputerName -prt $Port)
        }

        if ($Port) {
            $rslt | Add-Member -MemberType NoteProperty -Name 'RemotePort' -Value $Port
            $rslt | Add-Member -MemberType NoteProperty -Name 'TcpTestSucceeded' -Value (portKnock -cn $ComputerName -prt $Port)
        }

    }
    End {
        Return $rslt
    }
}
Set-Alias -Name Start-FastPing -Value Test-FastPing