Removing values from set in Batch - batch-file

I'm trying to write a script for work that tells me which machines on a network are online and which are offline.
Currently I have it showing me online/offline status, taking the PC names from a text file as input into a set variable.
The code I have so far is:
#echo off
setlocal EnableDelayedExpansion
for /F "tokens=*" %%a in (VC.txt) do call :append %%a
:ping
for %%i in (%VC) do (
ping %%1 -n 1 >nul
call :test %%i
)
echo.
goto :ping
:test
IF %ERRORLEVEL% EQU 0 (
echo Pinging %1
) else (
echo Off %1
)
goto :eof
:append
if defined VC (
set VC=%VC% %1
) else (
set VC=%1
)
What I want to happen is once a machine comes online, to remove it from the list. Basically just only show the list of the offline machines.
Is this possible without wiping the whole set and creating it fresh?

This mod do what you want:
:test
IF %ERRORLEVEL% EQU 0 (
echo Pinging %1
REM Remove this machine from the list
set "VC=!VC: %1=!"
) else (
echo Off %1
)
goto :eof
However, you have a couple small errors in your code. This is the fixed section:
:ping
for %%i in (%VC%) do (
ping %%i -n 1 >nul
call :test %%i
)
echo.
goto :ping
A couple points unrelated to your problem. If the machine names are single words with no spaces, then the "tokens=*" part in the for command is not needed. Also, all those call's and subroutines just complicate the code. This is the way I would do this:
#echo off
setlocal EnableDelayedExpansion
set "VC="
for /F %%a in (VC.txt) do set "VC=!VC! %%a"
:ping
for %%i in (%VC%) do (
ping %%i -n 1 >nul
IF !ERRORLEVEL! EQU 0 (
echo Pinging %%i
REM Remove this machine from the list
set "VC=!VC: %%i=!"
) else (
echo Off %%i
)
)
echo/
if defined VC goto :ping
echo All machines are on line

Related

Batch File Filter loop output

The code runs a very simple process of pinging multiple addresses endlessy and outputting the results to a log file until manually stopped.
#echo off
title ping_logger
set d1=%date:~4%
set d2=%d1:/=-%
set t1=%time::=.%
set t2=%t1: =%
set host=X.X.X.1;X.X.X.162
set hostname=%host:;=+%
set pinghostname=%host:;= and %
set logfile=Log_%hostname%_%ComputerName%_%d2%_%t2%.csv
setlocal enableextensions ENABLEDELAYEDEXPANSION
set counter=0
for %%A IN (%host%) DO (
set /a counter+=1
)
endlocal && set counter=%counter%
echo Target Host(s) = %host%>%logfile%
echo Pinging %pinghostname% with 32 bytes of data: >>%logfile%
timeout %counter% >NUL
:Ping
FOR %%A IN (%host%) DO (
for /F "tokens=* skip=2" %%A in ('ping %%A -n 1 ') do (
echo %date:~4%, %time:~0,2%:%time:~3,2%:%time:~6,2%, %%A>>%logfile%
echo %date% %time:~0,2%:%time:~3,2%:%time:~6,2%, %%A
)
)
IF (%counter% LSS 2) timeout 1 >NUL
GOTO Ping
The output is capturing too much into the log file. I'm looking to only get the first line from each response such as the highlighted lines
:DoPing
FOR %%A IN (%host%) DO (
set "pung="
for /F "tokens=* skip=2" %%A in ('ping %%A -n 1 ') do if not defined pung (
echo %date:~4%, %time:~0,2%:%time:~3,2%:%time:~6,2%, %%A>>%logfile%
echo %date% %time:~0,2%:%time:~3,2%:%time:~6,2%, %%A
set "pung=Y"
)
)
IF (%counter% LSS 2) timeout 1 >NUL
GOTO DoPing
(I'm allergic to using keywords/executable names as labels)
Simply set a flag value pung to nothing so that it is undefined when the pings start. On reporting the first line, set pung to non-empty, so it is then defined and the remining report lines are suppressed.
Next loop of %%A clears pung before issuing the ping for the next host...
Another way:
:DoPing
FOR %%A IN (%host%) DO (
for /F "tokens=1* skip=2" %%A in ('ping %%A -n 1 ') do if "%%A" == "Reply" (
echo %date:~4%, %time:~0,2%:%time:~3,2%:%time:~6,2%, %%A %%B>>%logfile%
echo %date% %time:~0,2%:%time:~3,2%:%time:~6,2%, %%A %%B
)
)
IF (%counter% LSS 2) timeout 1 >NUL
GOTO DoPing
This time, see whether the first token is the string Reply and only write the report if this is so.

How can we split string using windows bat

How can we split string using windows bat script?
for below .bat code snippet
#echo off & setlocal EnableDelayedExpansion
set j=0
for /f "delims=""" %%i in (config.ini) do (
set /a j+=1
set con!j!=%%i
call set a=%%con!j!%%
echo !a!
(echo !a!|findstr "^#">nul 2>nul && (
rem mkdir !a!
) || (
echo +)
rem for /f "tokens=2" %%k in(config.ini) do echo %%k
)
)
pause
below config file
Q
What's wrong when I del rem at the begin of rem for /f "tokens=2" %%k in(config.ini) do echo %%k
How can I get the /path/to/case and value as a pair?
for /f xxxx in (testconfig.ini) do (set a=/path/to/case1 set b=vaule1)
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q43407067.txt"
set j=0
for /f "delims=""" %%i in (%filename1%) do (
set /a j+=1
set con!j!=%%i
call set a=%%con!j!%%
echo !a! SHOULD BE EQUAL TO %%i
(echo !a!|findstr "^#">nul 2>nul && (
echo mkdir !a!
) || (
echo +)
for /f "tokens=2" %%k IN ("%%i") do echo "%%k"
for /f "tokens=1,2" %%j IN ("%%i") do echo "%%j" and "%%k"
)
)
ECHO ----------------------------
SET con
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q43407067.txt containing your data for my testing.
(These are setting that suit my system)
SO - to address your problems:
because the ) on that line closes the ( on the previous. The ) on that line closes the ( on the one prior. (I changed the rem to an echo so that the code would produce something visible) The first ( on the (echo !a! line is closed by the ) on the line following the (now) two for /f commands. and the ( on the for..%%i..do( is closed by the final ) before the echo -----
You can't delete that ) because it's participating in a parenthesis-pair.
You need a space between the in and the (.
I've shown a way. See for /?|more from the prompt for documentation (or many articles here on SO)
In your code, !a! is the same as %%i - so I've no idea why you are conducting all the gymnastics - doubtless to present a minimal example showing the problem.
Note that since the default delimiters include Space then if any line contains a space in the /path/to/case or value then you'll have to re-engineer the approach.
I' not sure if I understand what exactly it is you need, so what follows may not suit your needs:
#Echo Off
SetLocal EnableDelayedExpansion
Set "n=0"
For /F "Delims=" %%A In (testConfig.ini) Do (Set "_=%%A"
If "!_:~,1!"=="#" (Set/A "n+=1", "i=0"
Echo=MD %%A
Set "con[!n!]!i!=%%A") Else (For /F "Tokens=1-2" %%B In ('Echo=%%A'
) Do (Set/A "i+=1"
Set "con[!n!]!i!=%%B"&&Set/A "i+=1"&&Set "con[!n!]!i!=%%C")))
Set con[
Timeout -1
GoTo :EOF
remove Echo= on line 6 if you are happy with the output and really want to create those directories

Write line from 1 text file to a new text file, excluding the first 18 characters

I've searched many places and can't seem to come up with a solution to my problem. I have a .bat file that contains the following line:
rasdial "TEST VPN" username password
I would like to copy only the username and password to a new text file so it would just have:
username password
Everything I've found during my search does the exact opposite, leaving me with:
rasdial "TEST VPN"
Any help would be appreciated. I'm pretty sure this is easy, but I'm unable to figure it out on my own.
Thanks in advance!
Here's what I currently have:
#echo off
setlocal disableDelayedExpansion
set "ln1="
>"%USERPROFILE%\Desktop\credentials.txt" (
for /f "useback delims=" %%A in ("%USERPROFILE%\AppData\Roaming\Project Resources Group\PRG Connect\AutoKeepVPNAlive.bat") do (
if defined ln1 (
set "ln2=%%A"
setlocal enableDelayedExpansion
echo(!ln1!
endlocal
set "ln1="
)
for /f %%B in ("%%A") do if "%%B"=="rasdial" set "ln1=%%A"~18%
)
)
Contents of AutoKeepAliveVPN.bat are:
TITLE TEST Connect
#ECHO OFF
:loop
cls
set ip3=10.12.0.254
ping -n 1 %ip3% | find "Reply from %ip3%: bytes="
if %ERRORLEVEL%==0 (
goto loop2
) else (
goto connect
)
:loop2
cls
timeout 30
set ip1=google.com
ping -n 1 %ip1% | find "Lost = 0"
if not %ERRORLEVEL%==0 (
goto loop2
) else (
goto loop
)
:connect
cls
rasdial "TEST VPN" username password
if %ERRORLEVEL%==623 (
goto setup
) else (
net use P: "\\10.12.0.254\share"
goto loop
)
:setup
cls
CALL "%USERPROFILE%\AppData\Roaming\Project Resources Group\PRG Connect\VPN Setup.bat"
exit
This is a much simpler way to do what you need to do.
#echo off
for /f "delims=" %%G in ('findstr /B /I /C:"rasdial" "%USERPROFILE%\AppData\Roaming\Project Resources Group\PRG Connect\AutoKeepVPNAlive.bat"') do SET var=%%G
(echo %var:~18%)>>"%USERPROFILE%\Desktop\credentials.txt"

Batch file filtering out ping results

I have a script to continuously ping a set of machines (stored in SiteName.txt) and once a machine comes online, a counter increments, and the machine is removed from the list so it doesn't ping again (I just need to know if a machine has been online, not if it's on right now).
The issue I have is I've noticed there are a few phantom pings coming up with the IP address of the site they were built at (and that IP hasn't already been taken over by another machine) so I get false positives.
My current code is:
#echo off & setlocal EnableDelayedExpansion
TITLE %~n0
set /a counteron=0
for /F %%a in (%~n0.txt) do set "NVC=!NVC! %%a"
:ping
ping -n 61 127.0.0.1>nul
for %%i in (%NVC%) do (
ping %%i -n 1 | find "TTL=" >nul
if !errorlevel! GEQ 1 (
echo %%i is offline.
) else (
set /a counteron+=1
echo %%i is online
set "NVC=!NVC: %%i=!"
)
)
echo.
cls
echo. %counteron% machines are online.
if defined NVC goto :ping
cls
echo All machines in %~n0 are online.
pause
Is it possible to do the same thing, but if the IP's first 3 octets match a specific set (10.79.208.xxx), then it still comes up as offline?
Thanks in advance
Perhaps
ping %%i -n 1 | find "TTL=" |findstr /b /l /v /c:"Reply from 10.79.208." >nul
which should set errorlevel to zero only if both TTL= is found AND a line beginning (/b) with the /l literal string /c: "Reply from 10.79.208." is /v not found
which I believe is your quest...
Perhaps this slight alteration to your script is what you're after.
#echo off & setlocal enabledelayedexpansion
set nvc=192.168.1.1
for %%i in (%NVC%) do (
ping %%i -n 1 | find "TTL=" >nul
if !errorlevel! GEQ 1 (
echo %%i is offline.
) else (
for /f "tokens=1,2,3 delims=." %%j in ("%%i") do (
set octets=%%j.%%k.%%l
if "!octets!"=="10.79.208" (
echo %%i is false positive
) else (
set /a counteron+=1
echo %%i is online
set "NVC=!NVC: %%i=!"
)
)
)
)

Batch Script - Skip on errorlevel in a For loop

I am trying to have this script go to the next part if the error level of a ping to a computer does not equal 0, but I cannot get it to work. The output says the syntax is not correct. Thank you.
#echo
setlocal EnableDelayedExpansion
for /f %%a in (main.txt) do (
ping -n 1 %%a > NUL
IF %ERRORLEVEL%==0 (GOTO :COPY) ELSE GOTO :SKIP
:COPY
ROBOCOPY C:\Blah C:\Bloh
ECHO FILE COPIED
:SKIP
ECHO FILE NOT COPIED
)
You should try this:
#echo
setlocal EnableDelayedExpansion
for /f %%a in (main.txt) do (
ping -n 1 %%a >NUL
IF "!ERRORLEVEL!"=="0" (
ROBOCOPY "C:\Blah" "C:\Bloh"
ECHO FILE COPIED
) ELSE (
ECHO FILE NOT COPIED
)
)
PAUSE
There are a couple of things wrong with your code. First of all, you enable Delayed Expansion, but don't actually use it, only variables inside ! get expanded delayed. I also put quotes around your filepaths, to protect them against paths with spaces and stuff. Finally, goto and labels don't work inside for loops, so you need to replace them with if else logic
goto :Label inside a parenthesised block of code like for loops breaks the block/loop context, so the code at the label is executed as if it were outside of the block/loop. Therefore you need to work around that.
Dennis van Gils points out a way how to do it -- using if/else logic (his method as well as the following slightly modified snippet (applying numeric comparison) both require delayed expansion):
setlocal EnableDelayedExpansion
for "usebackq" /F %%A in ("main.txt") do (
> nul ping -n 1 %%A
if !ErrorLevel! EQU 0 (
robocopy "C:\Blah" "C:\Bloh"
echo FILE COPIED
) else (
echo FILE NOT COPIED
)
)
endlocal
Or like this, avoiding the necessity of delayed expansion:
for "usebackq" /F %%A in ("main.txt") do (
> nul ping -n 1 %%A
if ErrorLevel 1 (
echo FILE NOT COPIED
) else (
robocopy "C:\Blah" "C:\Bloh"
echo FILE COPIED
)
)
To check the ErrorLevel against (non-)zero, you can also use the && and || operators:
for "usebackq" /F %%A in ("main.txt") do (
> nul ping -n 1 %%A || (
echo FILE NOT COPIED
) && (
robocopy "C:\Blah" "C:\Bloh"
echo FILE COPIED
)
)
Finally, if you do want to keep the goto :Label structure, you need to use a sub-routine in order to move this part of the code outside of the () block (you also do not need delayed expansion here):
for "usebackq" /F %%A in ("main.txt") do (
> nul ping -n 1 %%A
call :SUB "C:\Blah" "C:\Bloh"
)
exit /B
:SUB
if %ErrorLevel% NEQ 0 goto :SKIP
robocopy "%~1" "%~2"
echo FILE COPIED
:SKIP
goto :EOF

Resources