Anyone who has been in IT long enough has performed a Ping Test. A simple ping and IP address. Most of us have used the “Ping 8.8.8.8 >> c:\pingtest.txt” to see how many times something failed. But did you know you can do the same thing with PowerShell? It’s also much cleaner and easier to understand. Unlike simple ping, we can see when the outage was, not just there was one. This helps to find logs easier.

The Script – Ping Test with PowerShell

function Test-Ping {
    <#
    .SYNOPSIS
        Sends an email using custom SMTP settings.
    .DESCRIPTION
        Sends an email using custom SMTP settings.
    .PARAMETER SecondsToRun
        [Int] How long the script will run. This will add the number of seconds to the current time. Then we will loop based off that input. Default is 24 hours
    .PARAMETER Outfile
        [string] The full path of where the CSV will go. 
    .PARAMETER SecondsToSleep
        [int] How many second will be between each test. Default is 1
    .PARAMETER IPaddress
        [ipaddress] The IP address that we want to test. Default is 8.8.8.8
    .PARAMETER Show
        [switch]Displays the output of the ping. 
    .EXAMPLE
        Test-Ping -SecondsToSleep 1 -IPaddress 8.8.4.4 -SecondsToRun 24 -Outfile c:\temp\google1.csv -show
        Pings 8.8.4.4 for 24 seconds at a one second interval. It appends the ping log to c:\temp\google1.csv and shows the output
            DateTime            IPaddress Latency  Status
            --------            --------- -------  ------
            2022-09-27_08_47_01 8.8.4.4        21 Success
            2022-09-27_08_47_02 8.8.4.4        11 Success
            2022-09-27_08_47_03 8.8.4.4        10 Success
            2022-09-27_08_47_04 8.8.4.4        10 Success
            2022-09-27_08_47_05 8.8.4.4        10 Success
            2022-09-27_08_47_06 8.8.4.4        10 Success
            2022-09-27_08_47_07 8.8.4.4        10 Success
    .EXAMPLE
            Test-Ping -SecondsToSleep 1 -IPaddress 8.8.4.4 -SecondsToRun 7 

            DateTime            IPaddress Latency  Status
            --------            --------- -------  ------
            2022-09-27_08_48_56 8.8.4.4        11 Success
            2022-09-27_08_48_57 8.8.4.4        10 Success
            2022-09-27_08_48_58 8.8.4.4        10 Success
            2022-09-27_08_48_59 8.8.4.4        12 Success
            2022-09-27_08_49_00 8.8.4.4        10 Success
            2022-09-27_08_49_01 8.8.4.4        10 Success
            2022-09-27_08_49_02 8.8.4.4        11 Success

            If you choose not to have an output of any type, the show will happen to have an output.
    .OUTPUTS
        PowerShell Custom Object
    .NOTES
        Author: David Bolding
        Date: 09/27/2022
    .LINK
        https:://therandomadmin.com
    #>
    [cmdletbinding()]
    param (
        [int]$SecondsToRun,
        [string]$Outfile,
        [int]$SecondsToSleep,
        [ipaddress]$IPaddress,
        [switch]$Show
    )

    #Determines if Seconds was delcared. 
    #if it wasn't, add 24 hours. If it was, add those seconds.
    if ($PSBoundParameters.ContainsKey('SecondsToRun')) {
        $Time = (Get-date).AddSeconds($SecondsToRun)
    }
    else {
        $Time = (Get-date).AddSeconds(86400)
    }

    #While current time is less than or equal to the added seconds.
    while ((get-date) -le $time) {

        #if IPaddress exists, we ping that ip address with test-connection with a count 1
        #if not, we ping google. 
        if ($PSBoundParameters.ContainsKey('IPaddress')) {
            $Test = Test-Connection $IPaddress -count 1 
        }
        else {
            $Test = Test-Connection 8.8.8.8 -count 1     
        }

        #Grabs current datetime in a readable string
        $DateTime = (Get-date).ToString("yyyy-MM-dd_hh_mm_ss")

        #Creates object
        $Results = [pscustomobject][ordered]@{
            DateTime  = $DateTime
            IPaddress = $test.address.IPAddressToString
            Latency   = $test.Latency
            Status    = $test.Status
        }

        #If outfile exists, drop the csv there and append
        #if not, display
        if ($PSBoundParameters.ContainsKey('Outfile')) {
            if ($Show) {
                $Results | Export-Csv -Path $Outfile -Append -NoClobber -NoTypeInformation
                $Results
            }
            else {
                $Results | Export-Csv -Path $Outfile -Append -NoClobber -NoTypeInformation
            }
            
        }
        else {
            #If no output is selected, we force an output with the else. 
            $Results
        }

        #if secondstosleep exists, we sleep by that many, if not, we sleep for 1 second. 
        if ($PSBoundParameters.ContainsKey('SecondsToSleep')) {
            start-sleep -Seconds $SecondsToSleep
        }
        else {
            Start-Sleep -Seconds 1
        }
    } 
}

The Breakdown

This function is designed to be quick. The idea is to quickly type Test-Ping and off to the races we go. You can set each parameter accordingly. We are going to work with 5 parameters. Firstly, “SecondsToRun” is for how long you want this script to run. Next, we have the “Outfile” parameter. This parameter is a full file path string. For example, c:\temp\pingtest.csv. Aftward, we have “SecondsToSleep”. This will be how long between intervals. Next, we want an IP address using the “IPaddress”. Finally, we have the show switch. So, if you select the csv output, if you want to see the output at the same time, you can trigger the show flag.

if ($PSBoundParameters.ContainsKey('SecondsToRun')) {
    $Time = (Get-date).AddSeconds($SecondsToRun)
} else {
    $Time = (Get-date).AddSeconds(86400)
}

The first part of the script is using the PSBoundParameter. This little guy lets you review what the end user puts into the function. In this case, we are looking for the key SecondToRun. If we have this key, we get the time that many seconds from now and place it into a variable. If we key isn’t present, we create a Time variable of 24 hours from now. Another way to go about this is by default the variable at the start. Then dropping it there.

The Loop

while ((get-date) -le $time) { #Do Something }

Afterward, we enter the loop. The idea behind the look is the current time has to be less than or equal to the $time variable we made in our last step.

if ($PSBoundParameters.ContainsKey('IPaddress')) {
    $Test = Test-Connection $IPaddress -count 1 
} else {
    $Test = Test-Connection 8.8.8.8 -count 1     
}

Like before, we are using the PSboundParameters and we are looking for the IPaddress. Here, if we have the IP address stated, we use the test-connection command and grab information about the IP address. if now, we use google. Like before, you can default the parameter as well to achieve the same results. It’s dependent on your goals.

#Grabs current datetime in a readable string
$DateTime = (Get-date).ToString("yyyy-MM-dd_hh_mm_ss")

#Creates object
$Results = [pscustomobject][ordered]@{
    DateTime  = $DateTime
    IPaddress = $test.address.IPAddressToString
    Latency   = $test.Latency
    Status    = $test.Status
}

Next, we grab the current date and create our PowerShell Custom Object. This is where it differs from simple ping and useful data. We have a date time. We have the latency and the status. As this is a PowerShell custom object, we can export this data, sort this data, and even more.

#If outfile exists, drop the csv there and append
#if not, display
if ($PSBoundParameters.ContainsKey('Outfile')) {
    if ($Show) {
        $Results | Export-Csv -Path $Outfile -Append -NoClobber -NoTypeInformation
        $Results
    } else {
        $Results | Export-Csv -Path $Outfile -Append -NoClobber -NoTypeInformation
    }           
} else {
    #If no output is selected, we force an output with the else. 
    $Results
}

What we do here with the data is we check if we want to output this data. if we do, we just dump it. If we want this data to show, we ask it to show with the show tag. Notice the -append flag on the export-csv. This means we are going to be adding to the file instead of rebuilding it. Thus a log. Now, if you don’t flag anything, we will have it show. This way we are not getting null.

#if secondstosleep exists, we sleep by that many, if not, we sleep for 1 second. 
if ($PSBoundParameters.ContainsKey('SecondsToSleep')) {
    Start-sleep -Seconds $SecondsToSleep
} else {
    Start-Sleep -Seconds 1
}

Finally, we sleep. This is our interval ratio. Like before, if it doesn’t exist, we use 1 second. If it does, we use that input. This could be done using the same default method.

Conclusion

In conclusion, this is designed to be part of your toolbox. So, if you want to ping your DNS server for 24 hours and see if there is anything wrong you can log it outside of the shell. I would suggest this function be in the profile of every machine on your network as it can save so much time with troubleshooting. It’s easy doing a Ping Test with PowerShell.

Additional reading:

Images by MidJourney AI