4

My google-fu has failed me. I've got a pretty simple script that just tests ping connectivity from one server to another, and displays a runtime at the top.

I'd like to be able to stop this script at any time with a single keypress ("q" in the script) and have it give some basic stats about how long it ran, and how many times it failed.

I can stop the script with ctrl+c, but that completely exits and doesn't allow me to show any stats. Below is my script. Any help is appreciated!

###############SETTINGS##########################

#Server to Ping:
$RemoteMachine = "ServerNameorIP"

#Seconds between each ping:
$PingInterval = 5

#File to log results:
$outFile = "C:\PingLog\"+$today+".PingLog.txt"

##################################################


$today = Get-Date -Format "yyyy-MM-dd"

#start a stopwatch for the progress bar
$elapsedTime = [system.diagnostics.stopwatch]::StartNew()

while ($true)
    {
   #Stick a progress bar at the top that shows elapsed time and how often we're pinging:
   write-progress -activity "Now testing ping connectivity to $RemoteMachine every $PingInterval seconds.  Press q to quit." -status "$([string]::Format("Time Elapsed: {0:d2}:{1:d2}:{2:d2}", $elapsedTime.Elapsed.hours, $elapsedTime.Elapsed.minutes, $elapsedTime.Elapsed.seconds))"

   $pingFails = 0

    #If the ping test fails, say something, and write it out to a log
    if(!(Test-Connection -ComputerName bb-ts-db -Quiet))
        {
        $pingFails++
        $dropTime = Get-Date -Format "MM/dd/yyyy - HH:mm:ss"
        Add-Content -Path $outfile -value ("Connection Lost at:  $dropTime")
        Echo "Connection Lost at $dropTime"
        }


    #Exit the loop if a key is pressed:
    if ($Host.UI.RawUI.KeyAvailable -and ("q" -eq $Host.UI.RawUI.ReadKey("IncludeKeyUp,NoEcho").Character)) 
    {
        Write-Host "Exiting now, don't try to stop me...." -Background DarkRed
        break;
    }

    #Wait the preset amount of time between each ping loop
    Start-Sleep $pingInterval
}


$elapsedTime.stop()

#Display the stats of this session:
echo "Test runtime:       $elapsedTime.Elapsed"
echo "# of failed pings:  $pingFails"

#If there WERE ping fails, write stats to $outFile
if($pingFails -gt 0)
{
    Add-content -Path $outfile -value "`n `n `n"
    Add-content -Path $outfile -value "Test runtime:       $elapsedTime.Elapsed"
    Add-content -Path $outfile -value "# of failed pings:  $pingFails"
}
user3242354
  • 41
  • 1
  • 1
  • 2
  • You could run your Pings as jobs, then do a `Do{}While((Get-Job -State Running))` loop though this kind of kills your whole progress bar bit. – TheMadTechnician Apr 10 '15 at 03:47

2 Answers2

4

Here is a simple example of using the [console]::KeyAvailable method. To make it usable, you will have to wake up your loop more often, and only execute ping on every 10th (,or so) wake up. (If that makes sense.)

$continue = $true
while($continue)
{
    if ([console]::KeyAvailable)
    {
        echo "Exit with `"q`"";
        $x = [System.Console]::ReadKey() 

        switch ( $x.key)
        {
            q { $continue = $false }
        }
    } 
    else
    {
        # Your while loop commands go  here......
        Start-Sleep -Milliseconds 500
    }    
}

Note: Unfortunately [console]::KeyAvailable does not work in PowerShelISE host so it is a pain to debug :(

Jan Chrbolka
  • 4,184
  • 2
  • 29
  • 38
0

This post is similar. There CTRL-C is captured and used to quit the loop/script.

Is there a way to catch ctrl-c and ask the user to confirm?

Community
  • 1
  • 1
jurgenb
  • 472
  • 4
  • 11
  • This works when you don't have start-sleep or another command that takes time to run, but once you do the start sleep, 99% of the time the script is running takes place outside of the if statement that is checking for the key press, which is the same problem I have above. Is there a way to have it check for the keypress at all times? – user3242354 Apr 09 '15 at 19:39