WinScp - Difficulty with handling error values - file

i am trying to write a simple winscp script to use it inside a for loop, in a batch file. The loop is :
for /F "tokens=2 delims==" %%s in ('set REMOTE_PATH[') do ("
ECHO CHECKING FOR %%s
winscp.exe /console /script=run01test1 /parameter // %%s
IF %ERRORLEVEL% neq 0 (
ECHO FILE %%s DOES NOT EXIST
CALL:error10 "76" "UNABLE TO LOCATE TARGET FILE %%s "
CALL:ERRORNOTIFYMAIL "UNABLE TO LOCATE TARGET FILE %%s" "FATAL" "CHECK EXISTENCE OF TARGET DIRECTORY" "77"
EXIT /B 10
) ELSE (
ECHO FILE %%s EXISTS
)
ECHO.
)
and the run01test1 winscp script is :
open sftp://xxx:xxx#xx.xx.xx.xx
stat "%1%"
exit
My problem is, that it either doesnt pass the parameter right, or for some reason the return value always returns zero whether the command stat succeeds or not. For the record, the idea is to check if files exist, the files are stored in an array in the style of :
set remote_path[0]
set remote_path[1]...
Can anyone help? Thanks in advance

You've got an delayed expansion problem with your %errorlevel% variable.
Either enable delayed expansion with setlocal enabledelayedexpansion and use !errorlevel! inside your code block, or use an alternative syntax:
if errorlevel 1 (...
which checks if errorlevel is 1 or higher. (see if /? for description)

Related

Batch file to edit .ini file but do not delete blank space

I am new to StackOverflow. I want to run a batch file to find and replace a single string in an .ini file. I tried several solutions given on stackoverflow and other sites too.
A few of them are working - but delete my other lines having "space" or ";".
Here is the string that I want to find and change in my file RDConfigSettings.ini
CommunicationMode:1
I want it vice-versa:
if it is "CommunicationMode:1" then change it to "CommunicationMode:0"
if it is "CommunicationMode:0" then change it to "CommunicationMode:1"
Here is the whole content of my RDConfigSettings.ini file
;0 for Staging, 1 for Pre-Production, 2 for Production
RDEnviroment:2
;0 for disable, 1 for Enable
RDServiceLogs:0
;0 for disable, 1 for Enable
ClientValidation:0
;Validate Management Server Certificate -- 0 for Yes, 1 for No
ValidateCertificate:0
;Proxy Configuration -- 0 for Direct Internet Access, 1 for Access via Proxy
ProxyConfig:0
ProxyIP:[Proxy IP]
ProxyPort:[Proxy Port]
;0 for Https, 1 for Http
CommunicationMode:1
;Port Range Setting in below field
PortBegin:11100
PortEnd:11120
;ManagementServerURL
Registration:https://rdm.smartbioplus.com/rdm-device-app/registration
Keyrotation:https://rdm.smartbioplus.com/rdm-key-management-app/keyRotation
Telemetry:https://rdm.smartbioplus.com/rdm-telemetry-app/telemetry
Domain:rdm.smartbioplus.com
URL_Port:443
Could anyone help me? THis is my code:
#echo off
set "file=E:\CSC Softwares\MorphoRdServiceL0Soft\RDConfigSettings.ini"
:loop
findstr "^CommunicationMode:0$" "%file%" >nul || (
type "%file%"|repl "^CommunicationMode:1" "CommunicationMode:0" >"%file%.tmp"
move "%file%.tmp" "%file%" >nul
)
timeout 120 >nul
goto :loop
Moreover, it will be a great help if someone can add an Command with administrative rights that will stop a particular service "MORPHO_RD_Service" before replacing the string and then after replace the string, start the same service again.
You have code to switch from 1 to 0, but no code to switch from 0 to 1.
Below code alternates between 1 and 0 with each run of the loop.
I also changed to jrepl (more modern and powerful). It isn't necessary (though possible) to process piped data and redirect the result to another file. The /f switch gives the inputfile to process, the /o switch gives the outputfile. By giving it a single -, it uses the same filename as the input file (and overwrites it with the new(changed) data).
#echo off
set "file=t.txt"
:loop
findstr "^CommunicationMode:" "%file%" & REM this line for troubleshooting only
findstr "^CommunicationMode:0$" "%file%" >nul && (
call jrepl "CommunicationMode:0" "CommunicationMode:1" /f "%file%" /o -
) || (
call jrepl "CommunicationMode:1" "CommunicationMode:0" /f "%file%" /o -
)
timeout 1 >nul
goto :loop
Don't forget to adapt the data file name and the timeout to your needs.
Without the need for an external utility such as jrepl, which is great for some things, but not needed for such a task:
#echo off
setlocal enabledelayedexpansion
set "file=E:\CSC Softwares\MorphoRdServiceL0Soft\RDConfigSettings.ini"
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>"%file%"') do (
set "line=%%j"
if "!line!" == "CommunicationMode:1" (
set "line=!line:1=0!"
set "hold=!line!"
) else if "!line!" == "CommunicationMode:0" (
set "line=!line:0=1!"
set "hold=!line!"
)
echo(!line!>>"!file!"
)
echo Changed to !hold!
pause

Changing a flag in the ini file from batch script

I have a script which will check if the file names and the content of the files are same or not, below is the code and it is working fine
ECHO OFF
CLS
for %%i in (C:\Users\f1ym41a\Documents\deep\*.DAT) do (
fc C:\Users\f1ym41a\Documents\deep\MOVE.DAT %%i > NUL
if errorlevel 1 (
CALL :error
echo C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are different >>output.log
) ELSE (
CALL :next
echo C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are same >>output.log
)
timeout 5
)
PAUSE
What i need to do is if the file names are same then it will change the flag in the ini file to 1. Below is the ini file (deep.ini)
[INI]
flag = 0
Since i am new to batch scripting. Can somebody help me out with this?
You can try with replacer.bat:
call replacer.bat move.dat "flag = 0" "flag = 1"
This is an easy to achieve task with using JREPL.BAT written by Dave Benham which is a batch file / JScript hybrid to run a regular expression replace on a file using JScript.
#echo off
if not exist "%USERPROFILE%\Documents\deep\MOVE.DAT" goto :EOF
if not exist "%~dp0jrepl.bat" goto :EOF
call "%~dp0jrepl.bat" "^(flag *= *)0" "$11" /F "%USERPROFILE%\Documents\deep\MOVE.DAT" /O -
The batch file first checks if the file to modify exists at all and immediately exits if this condition is not true, see Where does GOTO :EOF return to?
The batch file JREPL.BAT must be stored in same directory as the batch file with the code above. For that reason the batch file checks next if JREPL.BAT really exists in directory of the batch file and exits if this condition is not true.
The meaning of the regular expression search string is:
^ ... find at beginning of a line
(...) ... a string referenced in replace string with $1 to keep this part of found string unmodified
flag ... case-sensitive the string flag
 * ... with 0 or more spaces
= ... and an equal sign
 * ... and once more 0 or more spaces
0 ... and the character 0.
The replace string back-references the found string between beginning of line and character 0 with $1 and replaces 0 by 1.
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 also %~dp0 ... drive and path of argument 0 which is the batch file path always ending with a backslash.
echo /?
goto /?
if /?
jrepl.bat /?
:: 1st need remove some possible space in the string to got more precision
when compare them: "flag = 0" will became "flag=0", no
space and no tab.
:: 2nd for to do this, use this "' (2 characters) to set a variable that
use "=" to string instead a special character,
by set "'=flag=0" (very old technical!)
:: 3rd treat equal, treat tab character, and to remove it, because some time
this is a invisible and possible character that can eventually occur
in file dat, see in this question 10878138
:: 4th Compare the strings by string from file by file, line by line...
:: finely You need replace line in the file (.dat or .ini) this part I´m really confuse, but the code are above, sorry if my error!
Obs: use the conversion of this "flag = 0" this this one "flag=0", only for processing comparatives operation, wend the %%i match flag = 0 then only changed to replace to files by flag = 1, bat, a specific thing here is the command fc are comparing %%i, by the same file in looping for with no other file.
#echo off && setlocal EnableExtensions EnableDelayedExpansion
set "'=flag=0"
set _file_new_flag1="%temp%\Flag1.dat"
set _path_to_dats=C:\Users\f1ym41a\Documents\deep\
for /f "delims= " %%T in ('forFiles /p "." /m "%~nx0" /c "cmd /c echo(0x09"') do set "_tab=%%T"
type nul >output.log && set "_tab=%_tab:~0,1%"
cd /d "!_path_to_dats!"
for /f "tokens=* delims= " %%x in ('dir /o-d /on /b "*.dat"') do (
if defined _file_new_flag (
move /y "!_file_new_flag1!" "!_file_now!"
set _file_now=<nul
set "_file_now=%%~x"
) else (
set "_file_now=%%~x"
)
call :_file_compare_:
)
endlocal & goto :_end_of_file_:
:_file_compare_:
for /f "tokens=* delims= " %%X in ('type "!_file_now!"') do (
for /f "tokens=* delims= " %%i in ('echo/"%%~X"') do (
set "_to_compare=%%~i"
call set "_to_compare=!_to_compare: =!"
for /f "tokens=* delims=" %%I in ('echo/%_tab%') do call set "_to_compare=!_to_compare:%%I=!"
if ["!_to_compare!"] equ ["%'%"] (
echo/C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are same >>output.log
echo/%%~i>>!_file_new_flag1!
) else (
echo/C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are different >>output.log
echo/flag = 1>>!_file_new_flag1!
)
timeout /t 5
set _to_compare=<nul
)
)
exit /b
:_end_of_file_:
So sorry about my English.

Why doesn't my if statement block seem to be reached in batch?

I am facing a problem with my following batch script, where I can see how the execution of the command %nr% --f !path2! never seems to happen and I don't understand the reason.
What am I doing wrong? Too many nested conditions ?
EDIT: adding WRONG code where comments are enabled
rem The call to this batch script will be this
rem C:/Projects/DevelopmentTools/SDKs/TP/B/Scrpt/Exg_Serial_Flasher.bat EF.hex DH.hex C:/Projects/DevelopmentTools/SDKs/TP/B/E/Output/CN/Exe/
setlocal enabledelayedexpansion
set nr=nr.exe
if "%1"=="" (
if "%2"=="" (
if "%3"=="" (
echo "[Error]"
set "runScript="
)
)
) else (
set "input1=%1"
set "input2=%2"
set "path3=%3%nr%"
set "myPath"=%3"
set "path1=!myPath!!input1!"
set "path2=!myPath!!input2!"
rem Control variable
set "runScript=true"
)
if defined runScript (
if exist "%path3%" (
%nr% --check
if exist !path1! (
%nr% --f !input1!
echo !ERRORLEVEL!
if !ERRORLEVEL! EQU 0 (
echo !input1! set correctly
if exist !path2! (
echo Setting !exgSerial!
%nr% --f !input2!
if !ERRORLEVEL! EQU 0 (
echo Everything went fine
)
)
)
)
)
)
Thanks!
I suggest following batch code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ExeFile=nr.exe"
if "%~1" == "" goto ArgumentError
if "%~2" == "" goto ArgumentError
if not "%~3" == "" goto ProcessArguments
:ArgumentError
echo Error: %~nx0 must be called with three arguments.
exit /B 1
:ProcessArguments
rem Assign third argument to an environment variable.
set "FilePath=%~3"
rem Replace forward slashes by backslashes which is the directory separator on Windows.
set "FilePath=%FilePath:/=\%"
rem Make sure the file path ends with a backslash.
if not "%FilePath:~-1%" == "\" set "FilePath=%FilePath%\"
set "HexFile1=%FilePath%%~1"
set "HexFile2=%FilePath%%~2"
set "ExeFile=%FilePath%%ExeFile%"
if not exist "%ExeFile%" echo Error: "%ExeFile%" does not exist. & exit /B 2
if not exist "%HexFile1%" echo Error: "%HexFile1%" does not exist. & exit /B 3
if not exist "%HexFile2%" echo Error: "%HexFile2%" does not exist. & exit /B 3
"%ExeFile%" --check
"%ExeFile%" --f "%HexFile1%"
if errorlevel 1 echo Error: Processing "%HexFile1%" failed. & exit /B 4
"%ExeFile%" --f "%HexFile2%"
if errorlevel 1 echo Error: Processing "%HexFile2%" failed. & exit /B 4
echo Everything worked fine.
endlocal
An error condition is detected as soon as possible with resulting in exiting batch file processing with an appropriate error message and exit code.
There is no need for delayed environment variable expansion which makes processing the batch file faster and avoids problems with directory or file names containing an exclamation mark.
Name of a file or the file path can contain also command line critical characters like space or one of these characters &()[]{}^=;!'+,`~.
There are no nested IF conditions making successful execution flow straight from top to bottom.
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 %~1 which expands to argument 1 with removing any surrounding quotes.
echo /?
endlocal /? ... used here implicit on exiting batch file processing with exit and explicit at end of batch file.
exit /?
goto /?
if /?
rem /?
setlocal /?
See also Single line with multiple commands using Windows batch file.
I think I found the issue, it has to do with the fact that the "echos" to debug seem to influence the script execution. So in the code of my question, if I enable the echos, the script will fail running whereas if I disable them( commented out as below), the script does work.
Nevertheless, I don't understand why it does fail with the echos in first instance.
Code with disabled echos and working
rem The call to this batch script will be this
rem C:/Projects/DevelopmentTools/SDKs/TP/B/Scrpt/Exg_Serial_Flasher.bat EF.hex DH.hex C:/Projects/DevelopmentTools/SDKs/TP/B/E/Output/CN/Exe/
setlocal enabledelayedexpansion
set nr=nr.exe
if "%1"=="" (
if "%2"=="" (
if "%3"=="" (
echo "[Error]"
set "runScript="
)
)
) else (
set "input1=%1"
set "input2=%2"
set "path3=%3%nr%"
set "myPath"=%3"
set "path1=!myPath!!input1!"
set "path2=!myPath!!input2!"
rem Control variable
set "runScript=true"
)
if defined runScript (
if exist "%path3%" (
%nr% --check
if exist !path1! (
%nr% --f !input1!
rem echo !ERRORLEVEL!
if !ERRORLEVEL! EQU 0 (
rem echo !input1! set correctly
if exist !path2! (
rem echo Setting !exgSerial!
%nr% --f !input2!
if !ERRORLEVEL! EQU 0 (
echo Everything went fine
)
)
)
)
)
)

Proper error return code?

I have a small problem with my batch file, here is my code:
Java -jar ****name.jar -commands****
So incase the user does have java installed it should give proper error code and if it has java installed and the java does not find the file its trying to run it should give proper error code and so on.
If "%Errorlevel%" NEQ "0" (
For /F "Tokens=*" %%C In ('Net Helpmsg %Errorlevel%') Do (
Echo Error Level: [Return Code #%Errorlevel% - %%C]
)
)
I was hoping it would get me correct error codes but it doesn't. Like for example if the user does not have java installed it would say something like this "java is not recognized.." and it should give an correct error code beneath it but unfortunately, it doesn't.
Here is what i have tried:
Removed the quotation around Errorlevel so its does not treat it like a string.
I was hoping anyone could point out my mistake?
The error numbers used by net helpmsg and ErrorLevel are totally different things; net helpmsg only understands error numbers returned by the net command.
What you are trying to accomplish is the following, I think (take a look at the explanatory remarks):
rem /* Test whether `java` is installed and can be found: */
rem // simply try to run the `java` executable:
java -version 2> nul
if ErrorLevel 1 echo ErrorLevel is set to %ErrorLevel% [9009 if not found, 0 otherwise].
rem // or use the `where` command to find the `java` executable:
where java > nul 2> nul
if ErrorLevel 1 echo ErrorLevel is set to %ErrorLevel% [1 if not found, 0 otherwise].
if ErrorLevel 1 goto :EOF
rem /* Thest whether the Java script `name.jar` exists: */
rem // simply try to run the Java script:
java name.jar -commands 2> nul
if ErrorLevel 1 echo ErrorLevel is set to %ErrorLevel% [1 if not found, or, if the script exists, its `ErrorLevel`].
rem // or use the `where` command to find the `java` executable:
where name.jar > nul 2> nul
if ErrorLevel 1 echo ErrorLevel is set to %ErrorLevel% [1 if not found, 0 otherwise].
rem /* (the `> nul` suffix suppresses output messages,
rem the `2> nul` suffix suppresses error messages) */
rem /* To capture the error message returned by any command, do this: */
for /F delims^=^ eol^= %%E in ('
command 2^>^&1 ^> nul
') do (
echo This is the error message: "%%E"
)
Since the question post has been updated and clarified, the following does not cover the problem. The true solution can be found above. I keep the former answer here for reference.
This is for the case you want to extract the error number returned by the net command, which is specific to this command and has got nothing to to with the ErrorLevel:
The error number of the net command and the ErrorLevel are totally different things.
Supposing you try to execute net view, it might fail with this error message, for instance:
System error 6118 has occurred.
The list of servers for this workgroup is not currently available
The resulting ErrorLevel is 2 though.
So executing net helpmsg %ErrorLevel% does not make any sense.
In contrast, net helpmsg 6118 does, which returns the following string:
The list of servers for this workgroup is not currently available
To capture the error number of the net command, use a for /F loop and take the line of the first iteration only by an if defined condition (using command net view in this example):
set "ERRNUM=" & set "ERRTXT="
for /F "delims=" %%M in ('2^>^&1 ^> nul net view') do (
rem Note that the `token` option is language-dependent:
for /F "tokens=3" %%N in ("%%M") do (
if not defined ERRNUM set "ERRNUM=%%N"
)
set "ERRTXT=%%M"
)
This would capture the error number 6118 of the above example and store it in variable ERRNUM. The last line of the error output (that I consider as the error message) is stored in variable ERRTXT.
To retrieve the error message later from a given error number stored in ERRNUM, you could use this:
set /A "ERRNUM+=0"
if %ERRNUM% NEQ 0 (
for /F "delims=" %%M in ('net helpmsg %ERRNUM%') do (
set "ERRTXT=%%M"
)
)
Side Note: Yes, I would remove the quotes if %ErrorLevel% NEQ 0 to do a numeric comparison.

Set errorlevel in Windows batch file

I am writing a batch script that will loop through each line of a text file, (each line containing a filename) check if the file exists and then runs the file and moves it.
Here is my batch script:
REM Loop through each line of input.txt
FOR /F "tokens=1-3 delims=, " %%i IN (./ready/input.txt) DO (
ECHO.
ECHO.
ECHO.
ECHO Check %%i exists, set error flag if it doesnt
if not exist .\ready\%%i set errorlevel=2
echo return code is %errorlevel%
ECHO Run %%i if it exists
if errorlevel 0 call .\ready\%%i
ECHO Move %%i to archive if no error occured
if errorlevel 0 copy .\ready\%%i .\archive\%mydate%_%mytime%_%%j_%%k_%%i
ECHO Copy line of text to the new output.txt file if an error occured
if %errorlevel% NEQ 0 >>output.txt %%i, %%j, %%k
)
Here is the output:
I do not understand why the "if errorlevel" is not working as expected... if the file does not exist (as in this example where it does not exist) it should NOT try to run the file, it should NOT copy the file, and it should echo a 2 not a 0
Edit 1: I was reading another SO Post regarding "delayed environment variable expansion" I am not sure if this issue is related
ERRORLEVEL and %ERRORLEVEL% are two different variables. That means your code with echo return code is %errorlevel% and if %errorlevel% NEQ 0 >>output.txt %%i, %%j, %%k is probably wrong.
ERRORLEVEL is builtin and used to fetch the result of the last command. You can use it like:
IF ERRORLEVEL 1 ECHO error level is 1 or more
ERRORLEVEL cannot be set, just like bash does not let you set ?= ...
%ERRORLEVEL% is an environmental variable. If %ERRORLEVEL% is set, then its used in your script when you use %ERRORLEVEL%. If %ERRORLEVEL% is not set AND if command extensions are enabled, then it falls back to ERRORLEVEL. ERRORLEVEL does not update %ERRORLEVEL%.
Raymond Chen has a good blog entry on it: ERRORLEVEL is not %ERRORLEVEL%. Some of the content in this answer was shamelessly lifted from it.
#ECHO OFF
SETLOCAL
DEL output.txt 2>nul
REM Loop through each line of input.txt
FOR /F "tokens=1-3 delims=, " %%i IN (.\ready\input.txt) DO (
ECHO.
ECHO.
ECHO.
ECHO Check %%i exists, set error flag if it doesnt
if exist .\ready\%%i (set "errorflag=") ELSE (set errorflag=2)
CALL echo return code is %%errorflag%%
ECHO Run %%i if it exists
if NOT DEFINED errorflag (
call .\ready\%%i
ECHO Move %%i to archive if no error occured
if errorlevel 1 (SET errorflag=3) ELSE (ECHO copy .\ready\%%i .\archive\%mydate%_%mytime%_%%j_%%k_%%i)
)
ECHO Copy line of text to the new output.txt file if an error occured
if DEFINED errorflag >>output.txt ECHO %%i, %%j, %%k
)
GOTO :EOF
Here's a rewritten procedure.
Note: output.txt is deleted at the start, else the >> would append to any existing file. 2>nul suppresses error messages if the delete fails (eg. file not exist)
Within a block statement (a parenthesised series of statements), the ENTIRE block is parsed and THEN executed. Any %var% within the block will be replaced by that variable's value AT THE TIME THE BLOCK IS PARSED - before the block is executed.
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the chnaged value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.
IF DEFINED var is true if var is CURRENTLY defined.
ERRORLEVEL is a special varable name. It is set by the system, but if set by the user, the user-assigned value overrides the system value.
IF ERRORLEVEL n is TRUE if errorlevel is n OR GREATER THAN n. IF ERRORLEVEL 0 is therefore always true.
The syntax SET "var=value" (where value may be empty) is used to ensure that any stray spaces at the end of a line are NOT included in the value assigned.
The required commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO COPY to COPY to actually copy the files.
I used the following input.txt:
seterr1.bat, J1, K1
seterr5.bat,J2,K2
seterr0.bat,J3 K3
seterr5.bat, J4, K4
notexist.bat, J5, K5
With existing files seterr*.bat which contain
#ECHO OFF
EXIT /b 1
(where the 1 in the last line determines the errorlevel returned)
and received the resultant output:
Check seterr1.bat exists, set error flag if it doesnt
return code is
Run seterr1.bat if it exists
Move seterr1.bat to archive if no error occured
Copy line of text to the new output.txt file if an error occured
Check seterr5.bat exists, set error flag if it doesnt
return code is
Run seterr5.bat if it exists
Move seterr5.bat to archive if no error occured
Copy line of text to the new output.txt file if an error occured
Check seterr0.bat exists, set error flag if it doesnt
return code is
Run seterr0.bat if it exists
Move seterr0.bat to archive if no error occured
copy .\ready\seterr0.bat .\archive\__J3_K3_seterr0.bat
Copy line of text to the new output.txt file if an error occured
Check seterr5.bat exists, set error flag if it doesnt
return code is
Run seterr5.bat if it exists
Move seterr5.bat to archive if no error occured
Copy line of text to the new output.txt file if an error occured
Check notexist.bat exists, set error flag if it doesnt
return code is 2
Run notexist.bat if it exists
Copy line of text to the new output.txt file if an error occured
Note that the COPY is merely ECHOed as I mentioned earlier.
and output.txt
seterr1.bat, J1, K1
seterr5.bat, J2, K2
seterr5.bat, J4, K4
notexist.bat, J5, K5
Use something like the following subroutine:
:return
ECHO #exit /b %1 >ret.cmd
CALL ret.cmd
GOTO :eof
Then use it like this:
:Attempt
SETLOCAL
CALL somethingThatFails
SET retcode=!errorlevel!
CALL somethingThatPasses : don't care about the errorlevel here
CALL :return !retcode!
ENDLOCAL
CALL :eof
So, the whole thing would looke something like:
test.cmd...
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
CALL :Attempt
IF !errorlevel! NEQ 0 (ECHO Attempt Failed) ELSE (ECHO Attempt succeeded!)
GOTO :eof
:Attempt
SETLOCAL
CALL somethingThatFails
SET retcode=!errorlevel!
CALL somethingThatPasses : don't care about the errorlevel here
CALL :return %retcode%
ENDLOCAL
CALL :eof
:return
ECHO #exit /b %1 >return.cmd
CALL ret.bat
GOTO :eof
somethingthatfails.cmd...
DIR some command that fails >nul 2>&1
somethingthatpasses.cmd...
DIR >nul 2>&1
The one side effect of this is a file laying around called ret.cmd. I usually use an :end subroutine that does cleanup and would delete it.
There is an easy way to set the %errorlevel% with a trick I learned several years ago:
:: force errorlevel to 1
#(call)
echo %errorlevel%
:: force errorlevel to 0
#(call )
echo %errorlevel%
pause
The space after call is necessary to set the %errorlevel% to 0.
Update: After researching this, I found a reference here.
For posterity, when specifically setting it to 0, I like
ver >nul
ver.exe always returns 0.
This is designed to execute the %%i item only if it exists and follow through with checking for errors and move or log. if the %%i item doesn't exist then it will do nothing.
REM Loop through each line of input.txt
FOR /F "tokens=1-3 delims=, " %%i IN (.\ready\input.txt) DO (
ECHO.
ECHO.
ECHO.
ECHO Check %%i exists, execute it if it does
if exist .\ready\%%i (
call .\ready\%%i
ECHO Move %%i to archive if no error occured
if not errorlevel 1 (
copy .\ready\%%i .\archive\%mydate%_%mytime%_%%j_%%k_%%i
) else (
ECHO Copy line of text to the new output.txt file if an error occurred
>>output.txt %%i, %%j, %%k
)
)
)
for me, simple use of cmd /c exit 2 worked to set the errorlevel and use it locally in a batch file and even after it ended to ask for the errorlevel outside:
set errorlevel=2
:
cmd /c exit %errorlevel%
:
if errorlevel 3 echo 3
if errorlevel 2 echo 2
if errorlevel 1 echo 1
if errorlevel 1 echo 0
Results
>test.bat
2
1
0
>if errorlevel 2 echo 2
2

Resources