0

Basically I'm trying to read from a text file of servers, ping them continuously, and output a timestamp when each server has rebooted (find "Request timed out.")

for /f "delims=" %%a in (Servers_List.txt) do (
     start cmd /k ping -t %%a | find "Request timed out."
) && (Echo %%a rebooted at %time%.)

It launches each server ping -t in a separate window until I add the | find piece, and then it only launches one at a time after each subsequent window is closed.

Does anyone know a way to run each CMD window simultaneously without needing to close each prior window?

Thank you!

JosefZ
  • 28,460
  • 5
  • 44
  • 83
going_28
  • 3
  • 3
  • the pipe `|` waits for the proces (`ping -t`) to finish, before giving it's output to the next command (`find`); but `ping -t` doesn't finish... I', afraid, you'll have to build a loop on your own. – Stephan Mar 19 '15 at 15:32
  • Did you try cmd /c? /k tells it to leave the window open. – Matt Williamson Mar 19 '15 at 15:35

1 Answers1

1

Your design cannot work :-(

Your first problem is you are piping the output of your START command, but you want to pipe the output of PING. That can be fixed by escaping the pipe as ^|.

You have a similar problem with your conditional command concatenation - you would need ^&^& instead of &&1.

But the biggest problem is your ECHO will not execute until the pipe is closed, which is never! FIND will continue to look for additional timeout lines after the first one is detected. It will not end until after the pipe is closed, and your ECHO will not run until after FIND terminates.

Your best bet would be to write a VBScript, or JScript, or PowerShell script to continuously ping a server, and write out your message with timestamp when timeout is detected.

You could write a batch script to loop through your list of servers and start a new custom ping process for each one. Or you could put everything into a single VBScript (or JScript, or Powershell) script.

Perhaps one of the following links can help get you started:

http://windowsitpro.com/scripting/how-can-i-use-vbscript-script-ping-machine

http://www.sems.org/2013/07/little-vbscript-to-continously-ping-a-host-with-timestamplog/

https://thwack.solarwinds.com/docs/DOC-135033

I am assuming you ideally would like to have all output in a single screen. You can use the START /B option to run multiple processes within the same console window, but then you run the risk of garbled output if two processes attempt to write to the console at the same time. This can be solved via the exclusive lock that is obtained when a process opens a file for writing. See How do you have shared log files under Windows? for some pointers on how this can help. That link is for shared log files, but it is easily adapted for shared console access.

I have used my JREPL.BAT utility to hack up a solution. Architecturally this is a convoluted abomination, but it works! It runs an endless PING process for each server, all in parallel within the same console. Each process pipes its output to JREPL which detects if the server responded and writes out a time-stamped message to both the console and a log file. The log file is also used as a lock file to coordinated shared access between the processes. Each process keeps track of the last server status, and a message is only written when the status changes.

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment

::***** Batch code *******
@echo off
setlocal enableDelayedExpansion
set "first="
copy nul serverStatus.log >nul
for /f "delims=" %%A in (Servers_List.txt) do if not defined first (
  set "first=%%A"
) else (
  start /b cmd /c ping -t %%A ^| jrepl "^Request timed out|^Reply from " "log('%%A','DOWN')|log('%%A','UP')" /t "|" /jmatch /jlib "%~f0"
)
if defined first ping -t %first% | jrepl "^Request timed out|^Reply from " "log('%first%','DOWN')|log('%first%','UP')" /t "|" /jmatch /a /jlib "%~f0"
exit /b

****** JScript code ******/
var status = 'initial';
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file;

function log( server, newStatus ) {
  if (status!=newStatus) {
    status=newStatus;
    var msg=new Date().toString()+'  '+server+' is '+newStatus;
    while (!openFile());
    file.WriteLine(msg);
    output.WriteLine(msg);
    file.Close();
  }
  return false;
}

function openFile() {
  try {
    file = fso.OpenTextFile('serverStatus.log',8);
    return true;
  } catch(e) {
    return false;
  }
}

But, I don't see why it is necessary to run the processes in parallel. It seems to me you can simply enter an endless loop that cycles through the servers, and PINGs each server individually, writing out the status. Here is a simple batch script that does just that. Again, it only prints out a message when it detects a change in status.

@echo off
setlocal enableDelayedExpansion
for /l %%N in () do for /f "delims=" %%S in (Servers_List.txt) do (
  ping /n 1 %%S | findstr /bc:"Request timed out" >nul && set "status='DOWN'" || SET "status=UP"
  if "!status!" neq "!%%S!" (
    set "%%S=!status!"
    echo !date! !time!  %%S is !status!
  )
)
Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • Wow! Thank you for that extremely thorough response! Interestingly, you and I ended up deciding on similar techniques: – going_28 Mar 26 '15 at 01:45
  • Thank you for the thorough response! Interestingly, we resorted to similar techniques, regarding the ping -n 1 and looping: @ECHO OFF set /p server="Server for reboot check? " TITLE Pinging %server% since %time:~0,5%. :LOOP (ping -n 1 %server% | find "Request timed out." >nul) && (ECHO. & ECHO %server% rebooted at %time:~0,5%. & GOTO EXIT) || (CLS & Echo Pinging %server%...& GOTO LOOP) :EXIT ECHO. ECHO Press any key to exit... ECHO. PAUSE>nul Granted this is for singular use, it achieves the basic function. I will play with what you provided and see if I can adapt it. Thanks again! – going_28 Mar 26 '15 at 01:53
  • EDIT - Fixed a bug in the first solution with JREPL - the original code was writing to the console after the lock was released (file closed), which was no good. All fixed. – dbenham Mar 26 '15 at 02:11