Community Pick: Many members of our community have endorsed this article.
Editor's Choice: This article has been selected by our editors as an exceptional contribution.

Test IP Addresses with PING

Joe WinogradDeveloper
CERTIFIED EXPERT
50+ years in computers
EE FELLOW 2017 — first ever recipient of Fellow award
MVE 2015,2016,2018
CERTIFIED GOLD EXPERT
DISTINGUISHED EXPERT
Published:
Updated:
Edited by: David Draper
An Experts Exchange member requires a utility that accepts a file with a list of IP addresses and PINGs each of the addresses in the list. If there are any failures, the utility sends an email containing the IP addresses and error messages of all the failed PINGs. This article presents a solution.
Introduction

To solve the question posed by the Experts Exchange member, the method presented in this article requires AutoHotkey, an excellent (free!) programming/scripting language. The quick explanation for installing AutoHotkey is to visit its website and click the Download button. A more comprehensive explanation is in my EE article, AutoHotkey - Getting Started. After installation, AutoHotkey will own the AHK file type, supporting the solution discussed in the remainder of this article.

Features

• The utility, which I'm calling PingIPs, takes as input a plain text file with each IP address on a separate line, such as:

192.168.0.123
192.168.1.456
192.168.2.789


The attached script expects this file to be located in the same folder as the script itself with PingAddressList.txt as the file name. Of course, you may change the folder and/or file name to whatever you want by modifying this line in the script:

IPlist:=A_ScriptDir . "\PingAddressList.txt"

If the first column of a line is a semi-colon (;), that line is a comment and is ignored. If the first two columns of a line are slash-asterisk (/*), that line is a comment and it begins a comment block. If the first two columns of a line are asterisk-slash (*/), that line is a comment and it ends a comment block. All lines inside a comment block are ignored. These commenting features provide an easy way to "comment out" one or more IP addresses for a particular run. Also, blank/empty lines are ignored and may be used for readability.

PingIPs reads the file with the list of IP addresses and PINGs each one. It redirects the output of the PING command to a text file (via the command line ">" operator). The attached script expects this file to be in the same folder as the script itself with PingOutput.txt as the file name. Of course, you may change the folder and/or file name to whatever you want by modifying this line in the script:

PingOutput:=A_ScriptDir . "\PingOutput.txt"

It looks for a PING error message anywhere in the PING output file. Here are the PING error messages that I've either encountered myself or found on the web:

Destination Host Unreachable
Hardware Error
Ping request could not find host

Ping:transmit failed. General failure.
Request Timed Out
TTL Expired in Transit
Unknown Host


In earlier versions of the script, that message list was hard-coded in an array. In the current version, the list is in a plain text file for easier maintenance. The attached script expects this file to be located in the same folder as the script itself with PingErrorMessages.txt as the file name. Of course, you may change the folder and/or file name to whatever you want by modifying this line in the script:

PingErrorMessagesFile:=A_ScriptDir . "\PingErrorMessages.txt"

The current version of the PingErrorMessages.txt file (with the error messages shown above) is attached. Copy it into the same folder as the script, unless you decide to change its location and/or file name, as discussed above.

I never received the "Ping:transmit..." error message (found it on the web) and am concerned that the syntax shown above may not be precise, so I decided to enter that one in the file as two messages — transmit failed and general failure. This approach works because the string comparison used in the script is case insensitive and is a "contains" match (not an "equal" match). If you are aware of other PING error messages, please let me know by posting a comment below and I will add them to the article and the attached error messages file.

If the utility finds any of the error messages, it sends an email via SMTP with PING Error Notification as the Subject and with an email Body that looks like this:

The following PING errors occurred:
IP Address: 192.168.1.100 PING output: Request timed out.
IP Address: 192.168.2.150 PING output: Reply from 192.168.2.1: Destination host unreachable.

It sends an email only if at least one of the IP addresses resulted in a PING failure.

Of course, you may modify the script to change the Subject and Body of the email, as desired.

• Displays an icon in the system tray. The icon, a green checkmark to signify that it is "checking" IP addresses, looks like this (may vary based on the version of Windows, as it gets the icon from a built-in Windows file; also, may render a little differently in the tray):


• Displays a tooltip when hovering on the system tray icon. The tooltip has three lines:

• name of the script
• progress it has made by showing which item number it is working on, out of how many in the list
• current IP address being processed

It looks like this:


• Displays this context menu when right-clicking on the system tray icon:


• Selecting the About menu item displays a dialog box with a Title bar that contains the file name of the script without its path and file extension. The body of the dialog contains three lines:

• full path/name/extension of the script
• Version of the script as specified in the assignment statement on line 2 of the source code
• Modified date/time stamp of the script file

Here's an example of it:


Note that About acts to pause processing until the message box is dismissed.

• Selecting the Exit menu item exits (terminates/quits) the script, i.e., stops processing the IP address list. To make sure that this wasn't selected by accident, it displays this dialog, with No as the default button (so that an accidental Enter key won't cause an unwanted exit):


The Script — Source Code

Here is the script in a code block (also attached to the article as a file for easy downloading):

; Joe Winograd 26-Oct-2020
Version:="2.5"
#Warn,UseUnsetLocal ; warning on uninitialized variables
#NoEnv ; avoid checking empty variables to see if they are environment variables
#SingleInstance Force ; replace old instance immediately
SetBatchLines,-1 ; run at maximum speed

Gosub,InitializeVars ; initialize all variables
Gosub,ConfigureInitialTray ; configure initial system tray (notification area)
Gosub,ProcessPingList ; process ping list with IP addresses
ExitApp

InitializeVars:
SplitPath,A_ScriptName,,,,ProgramName ; ProgramName==>script name without path or extension
FileGetTime,ScriptDateTime,%A_ScriptName%,M ; modified time of script
FormatTime,ScriptDateTime,%ScriptDateTime%,yyyyMMdd-HHmmss
TrayIconFile:=A_WinDir . "\System32\shell32.dll" ; icon from this built-in file (need DLL that exists in XP-W10)
TrayIconNum:="-16802" ; green checkmark to indicate that it is "checking" server status
AtLeastOnePingError:=False
EmailBody:="The following PING errors occurred:"
IPlist:=A_ScriptDir . "\PingAddressList.txt"
If (!FileExist(IPlist))
{
  Msgbox,4112,Fatal Error,IP address list file does not exist:`n%IPlist%
  ExitApp
}
PingOutput:=A_ScriptDir . "\PingOutput.txt"
FileDelete,%PingOutput% ; delete output file
PingErrorMessagesFile:=A_ScriptDir . "\PingErrorMessages.txt"
If (!FileExist(PingErrorMessagesFile))
{
  Msgbox,4112,Fatal Error,PING error messages file does not exist:`n%PingErrorMessagesFile%
  ExitApp
}
; read all ping error messages into this array - matches are case insensitive and "Contains" (InStr), not "Equal"
PingErrorMessages:=[]
NumPingErrorMessages:=0
Loop,Read,%PingErrorMessagesFile%
{
  If (A_LoopReadLine="") ; in case there are blank/empty lines or an ending cr/lf
    Continue
  NumPingErrorMessages:=NumPingErrorMessages+1
  PingErrorMessages[NumPingErrorMessages]:=A_LoopReadLine
}
Return

ConfigureInitialTray:
Menu,Tray,NoStandard ; do not use standard AutoHotkey context menu
Menu,Tray,Add,&About,ContextMenu
Menu,Tray,Add,E&xit,ContextMenu
Menu,Tray,Default,&About
TrayTip:=ProgramName . " Version " . Version . "`nModified: " . ScriptDateTime
Menu,Tray,Tip,%TrayTip%
Menu,Tray,Icon,%TrayIconFile%,%TrayIconNum%
Return

ProcessPingList:
FileRead,IPaddr,%IPlist%
If (ErrorLevel=1)
{
  Msgbox,4112,Fatal Error,Error Level=%ErrorLevel% trying to read IP address list:`n%IPlist%
  ExitApp
}
CommentBlock:=False
NumIP:=0
Loop,Parse,IPaddr,`n,`r ; get number of IP addresses in list
{
  If (IsComment(A_LoopField)) ; ignore comments and blank lines
    Continue ; skip it
  NumIP:=NumIP+1 ; count it
}
If (NumIP=0) ; check number of un-commented lines
{
  Msgbox,4112,Fatal Error,There are no un-commented lines in IP address list:`n%IPlist%
  ExitApp
}
CurrentNum:=0 ; clear count
Loop,Parse,IPaddr,`n,`r ; process all IP addresses in list
{
  If (IsComment(A_LoopField)) ; ignore comments and blank lines
    Continue ; skip it
  CurrentNum:=CurrentNum+1 ; not a comment - bump the count
  CurrentIP:=A_LoopField
  TrayTip:=ProgramName . "`nProcessing address " . CurrentNum . " of " . NumIP . "`n" . CurrentIP
  Menu,Tray,Tip,%TrayTip%
  PingCmd:="ping " . CurrentIP . ">" . """" . PingOutput . """" ; quotes are needed in case there are spaces in the file name
  RunWait %comspec% /c """%PingCmd%""",,Hide ; ping IP address
  If (!FileExist(PingOutput)) ; check if ping created output file
  {
    EmailBody:=EmailBody . "`nIP Address: " . CurrentIP . " No output from PING"
    AtLeastOnePingError:=True
    Continue
  }
  Loop,Read,%PingOutput% ; process all lines in ping output file
  {
    CurrentLine:=A_LoopReadLine
    Loop,%NumPingErrorMessages% ; look for error message in current line
    {
      If (InStr(CurrentLine,PingErrorMessages[A_Index]))
      {
        AtLeastOnePingError:=True
        EmailBody:=EmailBody . "`nIP Address: " . CurrentIP . " PING output: " . CurrentLine
        Break 2 ; found error - do not need to process rest of Output file, so break inner and outer loop, but not IP list loop
      }
    }
  }
}
If (AtLeastOnePingError) ; there was at least one ping error - send email
{
  TrayTip:=ProgramName . "`nSending email"
  Menu,Tray,Tip,%TrayTip%
  ; fields for email
  pmsg:=ComObjCreate("CDO.Message")
  pmsg.From:="FromUser@gmail.com"                          ; *** change ***
  pmsg.To:="ToUser@whatever.com"                           ; *** change ***
  pmsg.Subject:="PING Error Notification"
  pmsg.TextBody:=EmailBody
  fields:=Object()
  fields.smtpserver:="smtp.gmail.com"
  fields.smtpserverport:=465
  fields.smtpusessl:=True
  fields.sendusing:=2
  fields.smtpauthenticate:=1
  fields.sendusername:="FromUser@gmail.com"                ; *** change ***
  fields.sendpassword:="password"                          ; *** change ***
  fields.smtpconnectiontimeout:=60
  schema:="http://schemas.microsoft.com/cdo/configuration/"
  pfld:=pmsg.Configuration.Fields
  For field,value in fields
    pfld.Item(schema . field):=value
  pfld.Update()
  Try pmsg.Send() ; send email - use Try so script won't show dialog upon Send error
}
FileDelete,%PingOutput% ; delete output file
Return

ContextMenu:
If (A_ThisMenuItem="&About")
{
  MsgBox,4160,About %ProgramName%,%A_ScriptFullPath%`n`nVersion %Version%`n`nModified: %ScriptDateTime%
  Return
}
If (A_ThisMenuItem="E&xit")
{
  MsgBox,4388,%ProgramName% - Terminate?,Are you sure you want to quit and stop processing the IP address list?
  IfMsgBox,No
    Return
  FileDelete,%PingOutput% ; delete output file
  ExitApp
}

IsComment(Line)
{
  global CommentBlock
  If (SubStr(Line,1,2)="/*") ; begin comment block
  {
    CommentBlock:=True
    Return True
  }
  If (SubStr(Line,1,2)="*/") ; end comment block
  {
    CommentBlock:=False
    Return True
  }
  If (CommentBlock) ; ignore everything inside a comment block
    Return True
  Return ((SubStr(Line,1,1)=";") or (Line="")) ; semi-colon in column 1 or blank line is a comment
}

It is important to note that you will have to change four lines in the script with your own information. Each of those lines has this beginning in column 60:

; *** change ***

The semi-colon signifies a comment in the AutoHotkey language.

Running PingIPs

PingIPs should work in all versions of Windows from XP through W10, both 32-bit and 64-bit, although I have tested it thoroughly only on W7 Pro 64-bit and W10 Pro 64-bit. Also, I tested it only with Gmail as the SMTP server, but you may change this in the source code. However, there are issues using the email feature of the script with an Exchange server due to the usage of CDO (Collaboration Data Objects). This is discussed thoroughly, including a work-around solution, at this EE thread:
Setup CDO for Office365

After downloading the script and modifying it with your information, you may run it by simply double-clicking it in Windows/File Explorer (or whatever file manager you use). Since its file type is AHK, AutoHotkey will be launched to run it. If you prefer, the file may be turned into an executable (an EXE file) via the AutoHotkey compiler, as explained in my AutoHotkey - Getting Started article.

It is important to note that PING errors other than the ones previously documented (and in the attached PingErrorMessages.txt file) will not be detected by this utility. However, it is easy to add other PING error messages for the script to check, as explained earlier in the article.

One of the design elements of PingIPs is that it produces no message boxes, GUIs, progress bars, or anything visible on the desktop or that would require user intervention, except in the case of a fatal error (such as failure to read the IP address list file) or explicit user request (such as the About and Exit context menu picks). The reason for this is to allow running the script periodically, such as every 10 minutes, in an unattended fashion. Creating a Task Scheduler job is a common way to do this. If you're not familiar with the Task Scheduler, my EE article will get you going on it:
How to use the Windows Task Scheduler - An Introduction

Conclusion

The attached AHK file contains the AutoHotkey script (a plain text file with the source code shown in the code block above). My hope is that the descriptive variable names along with the extensive comments in the script provide enough documentation for readers to modify it, but if you have any questions, post them here, and I'll try to assist.

If you find this article to be helpful, please click the thumbs-up icon below. This lets me know what is valuable for EE members and provides direction for future articles. Thanks very much! Regards, Joe

PingIPs.ahk
PingErrorMessages.txt
6
12,107 Views
Joe WinogradDeveloper
CERTIFIED EXPERT
50+ years in computers
EE FELLOW 2017 — first ever recipient of Fellow award
MVE 2015,2016,2018
CERTIFIED GOLD EXPERT
DISTINGUISHED EXPERT

Comments (45)

Joe WinogradDeveloper
CERTIFIED EXPERT
Fellow
Most Valuable Expert 2018

Author

Commented:
Hi Fred,
Thanks for sharing your script! Always a pleasure when members provide excellent feedback on articles and videos here at EE. Thanks, too, for the link to your article on delay times — reading it is now on my to-do list. :)  Regards, Joe
Andrew LeniartIT Professional, Freelance Journalist, Certified Editor
Author of the Year 2019
Distinguished Expert 2020

Commented:
Hi Joe,

Just had a thought about this little tool.

How about making the progress bar go red when pings fail, but green when they succeed?

Progress-Bar.jpg
I've no idea if that would be even possible to do?

It just occurred to me that it would be a really neat feature. If I'm dreaming about the impossible, feel free to ignore me :)
Joe WinogradDeveloper
CERTIFIED EXPERT
Fellow
Most Valuable Expert 2018

Author

Commented:
Hi Andrew,

That's a fascinating idea! But I don't see it happening, for two reasons. First, there's no way that I'm aware of to have multiple colors on the same progress bar...I can change colors on a progress bar, but the entire bar will be the same color.

Second, in thinking about how this script would most likely be used, I've decided to go in the opposite direction of your idea...no progress bar at all! My reasoning is that I expect the most usage of this to be unattended operation, probably via a Task Scheduler job that runs periodically, perhaps every few minutes (of course, it will be possible to run it on demand).

Thus, I decided to remove the progress bar and all message boxes...no user intervention (except for terminating it via the context menu...see below). There will be an icon in the system tray whose tooltip (when hovering on the icon) displays three lines: (1) the name of the script, (2) how much progress it has made by showing that it is working on address X of Y, and (3) the current address being processed. It looks like this:

tooltip
A right-click on the tray icon shows a very simple context menu:

context menu
I expect that the context menu will rarely be used, but it will provide two important features. First, the About choice will show the full path/name/extension of the script file, its version number, and its Modified date. More importantly, it acts to pause processing until the message box is dismissed. Second, the Exit choice will provide a way to exit/quit/terminate processing, i.e., discontinue processing the IP address list.

But I thank you for your always-creative ideas on improving my programs. Regards, Joe
Andrew LeniartIT Professional, Freelance Journalist, Certified Editor
Author of the Year 2019
Distinguished Expert 2020

Commented:
Thanks Joe. I suspected it wouldn't be easy and not really sure of what use it would be when it comes to monitoring Ping commands because if you're going to sit there and watch the thing, you may as well just stare at an open cli window. Just popped into my head so thought I'd share :)

Best, Andrew
Joe WinogradDeveloper
CERTIFIED EXPERT
Fellow
Most Valuable Expert 2018

Author

Commented:
Thanks for sharing, Andrew...I always appreciate your ideas for enhancements to my programs...and your excellent testing/bug-finding skills! Regards, Joe

View More

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.