Batch: How to store command output with spaces in variable? - batch-file

I want to make a Batch file to create windows firewall rules for an executable (for example, python). To do this, I have the following script:
REM ~ Open ports. Run with elevated administrator rights.
CALL :OPEN "python"
GOTO :EOF
:OPEN
IF ERRORLEVEL 1 (
GOTO :EOF
)
FOR /F %%i IN ('where %1') DO CALL :OPEN_PROGRAM "%1" %%i && GOTO :EOF
GOTO :EOF
:OPEN_PROGRAM
FOR %%j IN (TCP UDP) DO CALL :OPEN_PROGRAM_PORT %1 %2 "%%j"
GOTO :EOF
:OPEN_PROGRAM_PORT
netsh advfirewall firewall add rule name=%1 description=%1 dir=in action=allow edge=deferuser profile=private program=%2 protocol=%3
GOTO :EOF
This works fine as long as there are no spaces in the path to the executable.
If there are spaces in the path, then only the part up to the spaces is put in the %%i variable. I tried using 'where /F %1' , but then it still cuts the output on the space.
Is there a way to store the full output of where %1 in a variable? (Preferably without writing it to a file)

I would first advise you not to pass an filename without an extension. Doing so relies upon each of the extensions listed under %PATHEXT%, and you could have files named python.com, python.bat, python.cmd, python.vbs, python.vbe, python.js, python.jse, python.wsf, python.wsh, and python.msc, as well as python.exe. I'm sure you wouldn't want to unknowingly create firewall rules for all of those.
I would also advise that you do not use the where command for this. The reason being that it could return more than a single item. For example, try this, where notepad.exe and if memory serves, you'll probably see, C:\WINDOWS\System32\notepad.exe, followed by C:\WINDOWS\notepad.exe. That is because where.exe searches each location in %PATH% in order of their listing, and returns each, as the first two entries under %PATH% should by default be C:\WINDOWS\system32;C:\WINDOWS;.
My suggestion therefore would be to use another method, which returns the first item found under %PATH% as opposed to all, and this should, if you've used the variable properly, return the default, (most used) item. The method is the %~$PATH variable expansion, and is documented under the help information for the for command, i.e. entering for /? at the Command Prompt.
Example Script:
#Echo Off
SetLocal EnableExtensions
Rem ~ Open ports. Run with elevated administrator rights.
"%__AppDir__%reg.exe" Query HKU\S-1-5-19 1>NUL 2>&1 || (
Echo This script must be run elevated.
Echo Please use 'Run as administrator'
"%__AppDir__%timeout.exe" /T 3 /NoBreak 1>NUL
GoTo :EOF)
Call :OpenPorts "python.exe"
Pause
GoTo :EOF
:OpenPorts
For %%G In ("%~1") Do For %%H In (TCP UDP) Do (
"%__AppDir__%netsh.exe" AdvFirewall Firewall Add Rule^
Name="%~n1" Description="%~1" Dir=in Action=allow^
Edge=deferuser Profile=private Program="%%~$Path:G"^
Protocol=%%H)
Exit /B
I have removed all of the unnecessary Call commands, (using just the one), and deliberately used carets to split up your super long line, for readability; (which also allows you to include the localport= and/or remoteport= option, which I'd assume by your 'Open Ports' name you're going to want to include as a modification to the above later). I also took the liberty of including some code, to determine if the script was being run elevated, and display a message before closing, if it isn't.

Write the output of where.exe to a file, then read the file one line at a time. There is a way to do it without a temp file after the "===" line.
#ECHO OFF
SET "XTOFIND=%~1"
SET "TEMPFILE=%TEMP%\wherelist.tmp"
IF EXIST "%TEMPFILE%" (DEL "%TEMPFILE%")
"%__appdir__%where.exe" "%XTOFIND%" >"%TEMPFILE%"
FOR /F "tokens=*" %%A IN ('TYPE "%TEMPFILE%"') DO (
ECHO CALL :OPEN_PROGRAM "%%~A" %2 "%%J"
)
IF EXIST "%TEMPFILE%" (DEL "%TEMPFILE%")
ECHO ============
SET "XTOFIND=%~1"
FOR /F "tokens=*" %%A IN ('"%__appdir__%where.exe" "%XTOFIND%"') DO (
ECHO %%~A
ECHO CALL :OPEN_PROGRAM "%%~A" %2 "%%J"
)
EXIT /B 0

Related

Native cmd tail command for windows

I am looking to build a tail to read log files on windows using only native cmd.
There are various ways to to read a file:
type file.txt
more file.txt
They however do not have a default option to read updates from a file, so does not represent anything like tail.
With a few little hacks and using more to read the file, skipping what was already read before, we are able to tail the file, "almost" realtime.
#echo off & set cnt=0
if "%~1" == "" echo no file specified, usage: "tail.cmd <filename>" & goto :eof
if not exist "%~1" echo file "%~1" does not exist & goto :eof
:tail_sub
2>nul (>>"%~1" echo off) && (goto :file) || (goto :tail_sub)
:file
for /f "tokens=1*delims=]" %%i in ('more "%~1" +%cnt% ^| find /v /n ""') do (
set "line=%%j"
set /a cnt+=1
call echo(%%line%%
)
goto :tail_sub
Currently, without adding a timeout to slow down the infinite loop, it consumes around 5.6MB memory, which is very acceptable in my view.
This does not yet take care of all special characters, like |<>&, but I will spend some time on this to cater for all scenarios I can think off.

batch script - find and replace line that starts with specific value in an .ini file

Hello and firstly I would like to apologize for this post if it was already answered before. I spent the last 4 hours searching Stackoverflow and Google.
I have a gamesettings.ini file I would like to edit via batch file. I need to perform this over many PCs, so I would like to keep the other settings besides 2 lines in the file.
The two lines im trying to change are:
CustomVoiceChatInputDevice=Default Input
CustomVoiceChatOutputDevice=Default Output
I tried a few batch scripts I found on Stackoverflow, but they only work if I define the full line. Since every user has different options set, i need the script to just take the start of the line. Just "CustomVoiceChatInputDevice" for example.
Here's an example code I used, thanks to #jsanchez. This script doesn't work unless I type out the whole line:
Thank you for your time!!
#echo off
::Use the path from whence the script was executed as
::the Current Working Directory
set CWD=C:\
::***BEGIN MODIFY BLOCK***
::The variables below should be modified to the
::files to be changed and the strings to find/replace
::Include trailing backslash in _FilePath
set _FilePath=C:\Users\NEOSTORM\AppData\Local\RedDeadGame\Saved\Config\WindowsClient\
set _FileName=GameUserSettings.ini
::_WrkFile is the file on which the script will make
::modifications.
set _WrkFile=GameUserSettings.bak
set OldStr="CustomVoiceChatInputDevice"
set NewStr="CustomVoiceChatInputDevice=Line (Astro MixAmp Pro Game)"
::***END MODIFY BLOCK***
::Set a variable which is used by the
::search and replace section to let us
::know if the string to be modified was
::found or not.
set _Found=Not found
SETLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION
if not exist "%_FilePath%%_FileName%" goto :NotFound
::If a backup file exists, delete it
if exist "%_FilePath%%_WrkFile%" (
echo Deleting "%_FilePath%%_WrkFile%"
del "%_FilePath%%_WrkFile%" >nul 2>&1
)
echo.
echo Backing up "%_FilePath%%_FileName%"...
copy "%_FilePath%%_FileName%" "%_FilePath%%_WrkFile%" /v
::Delete the original file. No worries, we got a backup.
if exist "%_FilePath%%_FileName%" del "%_FilePath%%_FileName%"
echo.
echo Searching for %OldStr% string...
echo.
for /f "usebackq tokens=*" %%a in ("%_FilePath%%_WrkFile%") do (
set _LineChk=%%a
if "!_LineChk!"==%OldStr% (
SET _Found=Found
SET NewStr=!NewStr:^"=!
echo !NewStr!
) else (echo %%a)
)>>"%_FilePath%%_FileName%" 2>&1
::If we didn't find the string, rename the backup file to the original file name
::Otherwise, delete the _WorkFile as we re-created the original file when the
::string was found and replaced.
if /i "!_Found!"=="Not found" (echo !_Found! && del "%_FilePath%%_FileName%" && ren "%_FilePath%%_WrkFile%" %_FileName%) else (echo !_Found! && del "%_FilePath%%_WrkFile%")
goto :exit
:NotFound
echo.
echo File "%_FilePath%%_FileName%" missing.
echo Cannot continue...
echo.
:: Pause script for approx. 10 seconds...
PING 127.0.0.1 -n 11 > NUL 2>&1
goto :Exit
:Exit
exit /b
Each setting within your .ini file identifies the name of the setting. So the order of the lines should not may not matter.
If the line order is meaningless, then all you need do is use FINDSTR /V to remove the old values, and then simply append the new values. In the script below I modify both values at the same time.
#echo off
setlocal enableDelayedExpansion
set "iniLoc=C:\Users\NEOSTORM\AppData\Local\RedDeadGame\Saved\Config\WindowsClient"
set "iniFile=%iniLoc%\GameUserSettings.ini"
set "iniBackup=%iniLoc%\GameUserSettings.bak"
set "CustomVoiceChatInputDevice=Line (Astro MixAmp Pro Game)"
set "CustomVoiceChatOutputDevice=Some new value"
>"%iniFile%.new" (
findstr /vb "CustomVoiceChatInputDevice= CustomVoiceChatOutputDevice=" "%iniFile%"
echo CustomVoiceChatInputDevice=!CustomVoiceChatInputDevice!
echo CustomVoiceChatOutputDevice=!CustomVoiceChatOutputDevice!
)
copy "%iniFile%" "%iniBackup%"
ren "%iniFile%.new" *.
It would be slightly faster to create the backup file via rename instead of copy, but then there would be a brief moment where the ini file does not exist.
Windows command processor is not designed for editing text files, it is designed for running commands and applications.
But this text file editing/replacing task can be nevertheless done with cmd.exe (very slow):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileName=%LOCALAPPDATA%\RedDeadGame\Saved\Config\WindowsClient\GameUserSettings.ini"
set "TempFile=%TEMP%\%~n0.tmp"
if not exist "%FileName%" goto EndBatch
del "%TempFile%" 2>nul
for /F delims^=^ eol^= %%A in ('%SystemRoot%\System32\findstr.exe /N "^" "%FileName%"') do (
set "Line=%%A"
setlocal EnableDelayedExpansion
if not "!Line:CustomVoiceChatInputDevice=!" == "!Line!" (
echo CustomVoiceChatInputDevice=Line (Astro MixAmp Pro Game^)
) else if not "!Line:CustomVoiceChatOutputDevice=!" == "!Line!" (
echo CustomVoiceChatOutputDevice=Line (Astro MixAmp Pro Game^)
) else echo(!Line:*:=!
endlocal
) >>"%TempFile%"
rem Is the temporary file not binary equal the existing INI file, then move
rem the temporary file over existing INI file and delete the temporary file
rem if that fails like on INI file currently opened by an application with
rem no shared write access. Delete the temporary file if it is binary equal
rem the existing INI file because of nothing really changed.
%SystemRoot%\System32\fc.exe /B "%TempFile%" "%FileName%" >nul
if errorlevel 1 (
move /Y "%TempFile%" "%FileName%"
if errorlevel 1 del "%TempFile%"
) else del "%TempFile%"
:EndBatch
endlocal
See the answer on How to read and print contents of text file line by line? for an explanation of the FOR loop.
Please note the caret character ^ left to ) in the two lines to output. A closing parenthesis outside a double quoted argument string must be escaped here with ^ as otherwise ) would be interpreted by Windows command processor as end of command block and not as literal character to output by command ECHO. Other characters with special meaning for cmd.exe on parsing a command line or an entire command block like &|<> must be also escaped with ^ on ECHO command lines.
Please take also a look on Wikipedia article about Windows Environment Variables. It is highly recommended to use the right predefined environment variables for folder paths like local application data folder.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains %~n0 ... batch file name without path and file extension.
del /?
echo /?
endlocal /?
fc /?
findstr /?
for /?
if /?
move /?
rem /?
set /?
setlocal /?

How to write a batch script to read a text file line by line,match it with a regex and then edit the line in the same file

I am new to batch scripting
I am supposed to write a batch file to read a text file and two command line parameter say ,"task" and "choice".There can be two values for choice-"enable" and "disable"
Now i would want to input the file line by line and match the starting of line with "task" command line argument entered followed by a colon(:) followed by anything .
Now if the choice is "enable" then i have to put ":N" in the respective lines in which the task matches if it doesnt contain a :N already
My text file would contain entries like:
24343:abc:dsd:N
233:zxzxzc
2344:cxzc:xzc
and if i run a command like
myscript.bat 2344 enable
the output of the script should be that the file should be
24343:abc:dsd:N
233:zxzxzc
2344:cxzc:xzc:N
I have been trying to write the code for this for two whole days but still havent been successful.
After all the reading,this is what i have written till now
#echo off
set /A taskname= %1
set choice= %2
FOR /F "tokens=* delims=" %%x in (testdoc.txt) do (
echo %x%|findstr /R "^'%1'.*[^:][^N]$"
if errorlevel 1 (echo does not contain) else (echo contains)
)
In this,i was trying to compare line by line with the regex but it doesnt work as intended.
Any help would be appreciated
Thanks
Regular expression replaces are not possible with pure usage of Windows command line interpreter cmd.exe or the console applications installed with Windows. This would require usage of a scripting language/interpreter with support for regular expression replaces in files like PowerShell or JScript which would be most likely better choices for this task.
However, a pure batch file solution is also possible for this task as it can be seen on commented batch code below with lots of extra features.
#echo off
set "TempFile=
rem Is first parameter /? for getting help?
if "%~1" == "/?" goto ShowHelp
rem Is the batch file not started with any none empty parameter?
if not "%~1" == "" (
rem Does the first parameter not consist of only digits 0-9?
for /F "delims=0123456789" %%I in ("%~1") do goto ShowHelp
)
rem Is there also specified a second parameter?
if not "%~2" == "" (
rem Is the second parameter neither enable nor disable (case-insensitive)?
if /I not "%~2" == "disable" if /I not "%~2" == "enable" goto ShowHelp
)
rem Setup a local environment for this batch file.
setlocal EnableExtensions DisableDelayedExpansion
rem Define the name of the text file without or with path to modify.
rem Define the name of the temporary file needed to modify the file.
set "TextFile=TextFile.txt"
set "TempFile=%TEMP%\%~n0.tmp"
rem Does the text file to modify exist at all?
if not exist "%TextFile%" goto MissingFile
rem Was a task number specified on starting this batch file?
if not "%~1" == "" set "TaskNumber=%~1" & goto FindTask
rem Prompt the user for the task number and make sure that the user really
rem enters a number by verifying user input using a very secure method.
:PromptNumber
set "TaskNumber="
set /P "TaskNumber=Enter task number: "
if not defined TaskNumber goto PromptNumber
setlocal EnableDelayedExpansion
for /F "delims=0123456789" %%I in ("!TaskNumber!") do endlocal & goto PromptNumber
endlocal
:FindTask
rem Does the file to modify contain the number at beginning of a
rem line as specified with first parameter and followed by a colon?
%SystemRoot%\System32\findstr.exe /B /L /M /C:"%TaskNumber%:" "%TextFile%" >nul 2>&1
if errorlevel 1 goto MissingNumber
rem Has the user specified the action to perform as second parameter.
if /I "%~2" == "enable" set "TaskAction=1" & goto ModifyFile
if /I "%~2" == "disable" set "TaskAction=2" & goto ModifyFile
rem Prompt the user for the action to perform.
%SystemRoot%\System32\choice.exe /N /M "Press Y to enable or N to disable task: "
set "TaskAction=%ERRORLEVEL%"
rem Copy the file with ignoring empty lines and lines starting with a
rem semicolon to temporary file with modifying all lines starting with
rem the specified task number according to specified action to perform.
rem But delete the temporary file before if existing by chance.
:ModifyFile
del "%TempFile%" 2>nul
set "FileModified="
for /F "usebackq tokens=1* delims=:" %%I in ("%TextFile%") do (
if not "%%I" == "%TaskNumber%" (
echo %%I:%%J>>"%TempFile%"
) else (
set "TextLine=%%I:%%J"
call :ModifyLine
)
)
rem Was no line modified on copying all the lines to temporary file?
if not defined FileModified del "%TempFile%" & goto EndBatch
rem Move the temporary file over the text file to modify.
move /Y "%TempFile%" "%TextFile%" 2>nul
rem Was the text file overwritten by command MOVE?
if not errorlevel 1 goto EndBatch
rem Inform the user that the text file to modify could not be
rem modified because of being read-only or missing appropriate
rem NTFS permissions or a sharing access violation occurred.
del "%TempFile%"
for /F %%I in ("%TextFile%") do set "TextFile=%%~fI"
echo/
echo ERROR: "%TextFile%" could not be modifed.
echo/
echo Please make sure the file has not read-only attribute
echo set, is not opened in any application and you have
echo the necessary permissions to overwrite this file.
goto HaltBatch
rem This is a subroutine which modifies a line with right task
rem number according to action to perform and outputs this line
rem into the temporary file. It records also if the line needed
rem to be modified at all.
:ModifyLine
if %TaskAction% == 1 (
if not "%TextLine:~-2%" == ":N" (
set "TextLine=%TextLine%:N"
set "FileModified=1"
)
) else (
if "%TextLine:~-2%" == ":N" (
set "TextLine=%TextLine:~0,-2%"
set "FileModified=1"
)
)
>>"%TempFile%" echo %TextLine%
goto :EOF
rem Get name of file with full path which works also for not existing
rem file and inform the user about missing file to modify with full
rem path to see also where this batch file expected it on execution.
:MissingFile
for /F %%I in ("%TextFile%") do set "TextFile=%%~fI"
echo/
echo ERROR: "%TextFile%" does not exist.
goto HaltBatch
:MissingNumber
rem The specified number does not exist in the file to modify
rem at beginning of a line. Inform the user about this error.
echo/
echo ERROR: %TaskNumber% not found in file "%TextFile%".
goto HaltBatch
:ShowHelp
echo/
echo Usage: %~nx0 [task] [disable ^| enable]
echo/
echo task ...... number of the task to enable or disable.
echo disable ... disable the specified task.
echo enable .... enable the specified task.
echo/
echo %~nx0 can be also started without any parameter.
echo In this case the task number and the action to perform
echo can be entered during the execution of the batch file.
:HaltBatch
echo/
pause
echo/
:EndBatch
if defined TempFile endlocal
The command line set "TextFile=TextFile.txt" must be modified to your environment.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
choice /?
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
pause /?
rem /?
set /?
setlocal /?
Further read following:
DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/
Microsoft article about Using Command Redirection Operators
Stack Overflow answer on Where does GOTO :EOF return to?
Stack Overflow answer on Single line with multiple commands using Windows batch file

Search file with wildcard path

I want to write a script to prompt user for file path and list all files found. The file path can contain wildcards. Something similar to this. But the batch script version of it. For example:
C:\Somewhere\user*\app\version-*.*\start.exe
The files might be located like this:
C:\Somewhere\user345\app\version-1.0\start.exe
C:\Somewhere\user898\app\version-1.2\start.exe
C:\Somewhere\user898\app\version-1.3\start.exe
I tried to use FOR and it turns out to be so much harder than expected because FOR does not support wildcards in the middle of a path.
Is there a way to list these files? (Maybe without using for?)
I think this recursive solution works pretty well; you may name it WCDIR.bat:
#echo off
setlocal
if "%~1" neq "" set "next=%~1" & goto next
echo Show files selected by several wild-cards
echo/
echo WCDIR wildcardPath
echo/
echo Each folder in the path may contain wild-cards
echo the last part must be a file wild-card
goto :EOF
:next
for /F "tokens=1* delims=\" %%a in ("%next%") do set "this=%%a" & set "next=%%b"
if defined next (
for /D %%a in ("%this::=:\%") do (
setlocal
cd /D "%%~a" 2>NUL
if not errorlevel 1 call :next
endlocal
)
) else (
for /F "delims=" %%a in ('dir /B /A:-D "%this%" 2^>NUL') do echo %%~Fa
)
exit /B
EDIT: I fixed a small bug in the last for /F command.
For example, the output of WCDIR.bat C:\Windows\Sys*\find*.exe command in my Windows 8.1 64-bits computer is:
C:\Windows\System32\find.exe
C:\Windows\System32\findstr.exe
C:\Windows\SysWOW64\find.exe
C:\Windows\SysWOW64\findstr.exe
You can try with the command Where /?
The WHERE command is roughly equivalent to the UNIX 'which' command. By default, the search is done in the current directory and in the PATH.
#echo off
Where /R "%programfiles%" *winrar.exe
pause
#echo off
:: Example d'input
set UserInput=*drive*
:: building the Pattern
set cmd=%Userinput%.exe
:: storage Where.exe command in a macro, the execution will be faster
set whereCmd=where.exe /r c:\windows\ %cmd%
:: execution of macro and output formatting
for /f %%a in ('%whereCmd%') do echo %%~nxa --^> %%a
pause

Two For Loops Using %1 - Delayed Expansion?

My working batch file scans a long list of remote servers, copies anything there to a local server, checks the log file for a keyword, and if the keyword is found sends an email. I noticed it is always sending emails, even with a blank log file.
I discovered both FOR loops are using the %1 variable for their output - as seen in ECHO %1 and each line of the called :servermove. For lack of a better explanation it is not resetting %1 to null between loops.
I reviewed almost a dozen SO posts and am somewhat confident using SETLOCAL ENABLEDELAYEDEXPANSION would resolve this. That is where my understanding ends and I am unsuccessful thus far.
Here is the relevant code:
SET DATE=%date:~4,2%-%date:~7,2%-%date:~10,4%
SET HH=%time:~0,2%
SET MN=%time:~3,2%
SET TSTAMP=Time Run is %HH%%MN%
SET DATETIME=%DATE% at %HH%%MN%
SET LOGFILE="\\nt980a3\CreditFileImagesTransmission\LogFiles\%DATETIME%-File Move Log.txt"
SET MailDst=
SET MailSrc=
SET MailSrcName=Center to LDSD File Mover
SET OKMailSub=A Branch Has Sent You Some Files
ECHO %DATETIME% > %LOGFILE%
ECHO. >> %LOGFILE%
FOR /F "tokens=1" %%A IN (%~dp0SourceServers.txt) DO CALL :ServerMove %%A
:cleanuplogs
PUSHD "\\nt980a3\CreditFileImagesTransmission\LogFiles" &&(
FORFILES /S /M *.txt /D -45 /C "CMD /C DEL /Q #path"
) & POPD
:mailtest
FOR /F "tokens=*" %%A IN (%LOGFILE%) DO CALL :searchlog "%%A"
:searchlog
ECHO %1 | find "\\nt">NUL
IF NOT ERRORLEVEL 1 GOTO successmail
GOTO exit
:successmail
IF EXIST %temp%\to.txt DEL %temp%\to.txt
FOR %%a IN (%MailDst%) DO ECHO %%a>>%temp%\to.txt
"%~dp0sendmail.exe" /TO=%temp%\to.txt /FROM=%MailSrcName% ^<%MailSrc%^> /REF=%OKMailSub% /MESSAGE=%LOGFILE% /HOST=
:exit
EXIT
:ServerMove
DIR /S /B \\%1\CreditFileImagesTransmission\*.* >> %LOGFILE%
XCOPY /E /C /I /Y "\\%1\CreditFileImagesTransmission\*.*" "\\nt980a3\CreditFileImagesTransmission\%DATE%\%HH%%MN%\"
FOR /D %%P IN ("\\%1\CreditFileImagesTransmission\*.*") DO RMDIR "%%P" /Q /S
DEL /Q /S "\\%1\CreditFileImagesTransmission\*.*"
I tried changing :mailtest to use %%B in both instances but that also fails. Placing SETLOCAL ENABLEDELAYEDEXPANSION and its counterpart ENDLOCAL before one or the other loop and changing the %%A to !A! does not work either.
Would someone kindly point out the error in my ways and offer suggestions or resources that will help me resolve this?
%1 is the first parameter provided to the procedure - either from the command-line (in the main procedure) or the parameter following the procedure name in call :procedurename parameter1.
In your case, %1 to :servermove is an entry from SourceServers.txt and %1 to :searchlog is each line from %LOGFILE%.
Since you've censored your batch, what you've posted makes little sense. For instance, the :searchlogs routine will take the first line from %LOGFILE% and go to successmail or cleanlogs depending on whether that first line contains the target string \\nt. What it does from there, we can't tell.
We're faced with an XY problem - trying to fix a solution, not a problem.
First problem: Don't use date as a user-variable. It's a "magic variable" which contains the date but it's overridden by a specific set statement.
Having run :servermove for each entry in SourceServers.txt, you are
- accumulating a directory list from \CreditFileImagesTransmission\*.* on that server.
- copying those files to server nt980a3 with a date/timestamp but not including the source-servername so any duplicate name anywhere will overwrite an earlier version. I suggest you include %1 into your destination-name.
- deleting subdirectories
- deleting files.
I'd suggest you simply remove the directory \\%1\CreditFileImagesTransmission\, then re-create it.
I'd also suggest that you add an extra line
goto :eof
after the del /q /s... line. This will cause execution to be transferred to the end-of-file (the colon in :eof is required) and may seem superfluous, but it ensures that the routine has a defined endpoint - if you add a further routine, there is no way the :servermove routine will continue into your new code.
After each server has been processed, you proceed to the :cleanuplogs routine, which I presume deletes logs older than 45 days.
Your next statement is a real problem. What it will do is grab the very first line of the logfile (which contains "%DATE% at %HH%%MN%" with the date resolved as you've set at the start and it then processes this line in :searchlog; there is no \\nt in this line, so errorlevel is set to 1, and the batch proceeds to :EXIT (not a good label in my view, since it's a keyword); executes an exitand should terminate the batch.
This appears not to be what it is actually doing, and I'm at a loss to explain why.
I'd suggest changing
:mailtest
FOR /F "tokens=*" %%A IN (%LOGFILE%) DO CALL :searchlog "%%A"
:searchlog
ECHO %1 | find "\\nt">NUL
IF NOT ERRORLEVEL 1 GOTO successmail
GOTO exit
to
:mailtest
find "\\nt" %LOGFILE%>NUL
IF NOT ERRORLEVEL 1 GOTO successmail
:failmail
echo "\\nt" was found in the log
pause
GOTO exit
but I can't test that...
:mailtest
FOR /F "tokens=*" %%A IN (%LOGFILE%) DO CALL :searchlog "%%A"
You are missing a GOTO :EOF or similar goto here because it will drop through to the routine below once the above is finished.
:searchlog
ECHO %1 | find "\\nt">NUL
IF NOT ERRORLEVEL 1 GOTO successmail
GOTO exit
I feel you can not carry the %1 of first for loop to others. Try to transfer that to another variable like below.
:ServerMove
set servername=%1
DIR /S /B \\%servername%\CreditFileImagesTransmission\*.* >> %LOGFILE%
XCOPY /E /C /I /Y "\\%servername%\CreditFileImagesTransmission\*.*" "\\nt980a3\CreditFileImagesTransmission\%DATE%\%HH%%MN%\"
FOR /D %%P IN ("\\%servername%\CreditFileImagesTransmission\*.*") DO RMDIR "%%P" /Q /S
DEL /Q /S "\\%servername%\CreditFileImagesTransmission\*.*"
Cheers, G

Resources