How can I display a description based on errorlevel value? - batch-file

I'm writing a batch script to install an exe and a successful installation returns 0 and other codes mean different reasons.
I know I can print those error code(s) by echo %errorlevel%
Can I print the description related to the code instead? If so, how?
i.e. print 'successful' for code 0, etc.

Add below lines to print a message using error codes
if %errorlevel% equ 0 echo Successful
if %errorlevel% NEQ 0 echo Not Successful
Because errorlevel 0 indicates that return values of last executed command is successful,other return values have their own meaning

You can use || to act on failure, for simplicities sake this should do fine.
if %errorlevel% equ 0 echo Installed! || echo Install failed...
And && to activate on success.
del file.ext && echo File deleted.
The reason I don't provide a per errorlevel basis is that there can be up to 255 of them, something that would take an exceedingly high amount of time, and is further hindered by the tendency of programs not publically showing or ever documenting what each and every errorlevel means.
Something good to keep in mind is the difference between %errorlevel% and errorlevel. here

Related

Which cmd.exe internal commands clear the ERRORLEVEL to 0 upon success?

A frequent method to handling errors within Windows batch scripts is to use things like
if errorlevel 1 ... or if %errorlevel% neq 0 .... Often times one wants the error handling code to preserve the ERRORLEVEL.
I believe all external commands will always result in ERRORLEVEL being set to some value, so the error handling code must preserve the ERRORLEVEL in an environment variable prior to executing an external command.
But what about internal commands? The problem is, some internal commands clear the ERRORLEVEL to 0 when they succeed, and some do not. And I can't find any documentation specifying which commands do what.
So the question is, which internal commands clear the ERRORLEVEL to 0 upon success? This is not a general question about returned ERRORLEVEL codes, but strictly about success results.
There are posts like What is the easiest way to reset ERRORLEVEL to zero? and Windows batch files: .bat vs .cmd? that give partial answers. But I have never seen a comprehensive list.
Note: I've been curious about this for years. So I finally decided to run a bunch of experiments and come up with a definitive answer. I'm posting this Q&A to share what I have found.
This answer is based on experiments I ran under Windows 10. I doubt there are differences with earlier Windows versions that use cmd.exe, but it is possible.
Also note - This answer does not attempt to document the ERRORLEVEL result when an internal command encounters an error (except for a wee bit concerning DEL and ERASE)
Not only are there difference between commands, but a single command can behave differently depending on whether it was run from the command line, or within a batch script with a .bat extension, or from within a batch script with a .cmd extension.
The following set of commands never clear the ERRORLEVEL to 0 upon success, regardless of context, but instead preserve the prior ERRORLEVEL:
BREAK
CLS
ECHO
ENDLOCAL
FOR : Obviously, commands in the DO clause may set the ERRORLEVEL, but a successful FOR with at least one iteration does not set the ERRORLEVEL to 0 on its own.
GOTO
IF : Obviously, commands executed by IF may set the ERRORLEVEL, but a successful IF does not set ERRORLEVEL to 0 on its own.
KEYS
PAUSE
POPD
RD
REM
RMDIR
SHIFT
START
TITLE
The next set of commands always clear the ERRORLEVEL to 0 upon success, regardless of context:
CD
CHDIR
COLOR
COPY
DATE
DEL : Always clears ERRORLEVEL, even if the DEL fails (except when run without any file argument).
DIR
ERASE : Always clears ERRORLEVEL, even if ERASE fails. (except when run without any file argument).
MD
MKDIR
MKLINK
MOVE
PUSHD
REN
RENAME
SETLOCAL
TIME
TYPE
VER
VERIFY
VOL
Then there are these commands that do not clear ERRORLEVEL upon success if issued from the command line or within a script with a .bat extension, but do clear the ERRORLEVEL to 0 if issued from a script with a .cmd extension. See https://stackoverflow.com/a/148991/1012053 and https://groups.google.com/forum/#!msg/microsoft.public.win2000.cmdprompt.admin/XHeUq8oe2wk/LIEViGNmkK0J for more info.
ASSOC
DPATH
FTYPE
PATH
PROMPT
SET
Lastly, there are these commands that do not fit neatly into any of the prior categories:
CALL : If a :routine or batch script is CALLed, then ERRORLEVEL is exclusively controlled by the CALLed script or :routine. But any other type of successful CALL to a command will always clear ERRORLEVEL to 0 if the CALLed command does not otherwise set it.
Example: call echo OK.
EXIT : If used without /B, then the cmd.exe session terminates and there is no more ERRORLEVEL, just the cmd.exe return code. Obviously EXIT /B 0 clears the ERRORLEVEL to 0, but EXIT /B without a value preserves the prior ERRORLEVEL.
I believe that accounts for all internal commands, unless there is an undocumented command that I missed.
Your description of CALL command is incomplete:
CALL : Clears ERRORLEVEL if the CALLed command does not otherwise set it.
Example: call echo OK.
Check this small example:
#echo off
call :setTwo
echo Set two: %errorlevel%
call :preserve
echo Preserve: %errorlevel%
call echo Reset
echo Reset: %errorlevel%
call :subNotExists 2> NUL
echo Sub not exist: %errorlevel%
goto :EOF
:setTwo
exit /B 2
:preserve
echo Preserve
exit /B
Output:
Set two: 2
Preserve
Preserve: 2
Reset
Reset: 0
Sub not exist: 1
CALL description should say something like this:
CALL : Clears ERRORLEVEL if the CALLed command does not otherwise set it. Example: call echo OK, but if the called command is a subroutine it preserves the prior ERRORLEVEL. If the called subroutine does not exist, it sets the ERRORLEVEL to 1.

Is Windows %ERRORLEVEL% == $? in Linux

Trying my hands on windows batch files, in the below code that I found by searching in www.
#ECHO OFF
REM Call this with two arguments, and it will add them.
SET a=%1+%2
IF %ERRORLEVEL%==0 (goto errors-0) ELSE (goto errors-1)
REM Instead of using goto with the variable, this uses an IF-ELSE structure
:errors-0
REM This is if it was successful
ECHO %a%
goto exit
:errors-1
REM this is if it had an error:
ECHO Errors occurred.
goto exit
REM GUESS WHAT, THIS REM WILL NEVER EVER BE READ! IT WILL BE SKIPPED OVER BY THE GOTOS
:exit
ECHO.
ECHO press any key to exit.
PAUSE>nul
The code is suppose to take 2 arguments, add them and echo the result.
But this won't execute with success on my Windows 8.1 machine. Below is what I get:
C:\ProjectDoc>add3.bat
Errors occurred.
press any key to exit.
So, U added an echo for the ERRORLEVEL to see its value after executing the command SET. Below is the output:
C:\ProjectDoc>add3.bat 2 3
9009
Errors occurred.
press any key to exit.
C:\ProjectDoc>
So, is this errorlevel in Windows equal to the $? of Linux. Should it be returning 0 for every successful execution of a command or is it different? Reading some docs relates it to the Linux $? but it isn't clearly working as $? in Linux.
Yes, to be precise, %errorlevel% is analogous to $? in Bash shell.
In your batch file, SET a=%1+%2 is not doing what you expect it to do. It just sets the value of the variable a to the string "2+3" assuming you ran the file with arguments 2 3. If you want to do arithmetic you need to use the /A option: set /a a=%1+%2.
The SET command (and many other built-in commands) only set the ERRORLEVEL if there has actually been an error. If it was successful, the ERRORLEVEL will retain its previous value. I think this is what you're witnessing in your question.
By contrast, when a command runs an executable file, when the process completes it always sets the ERRORLEVEL.
As well as checking the ERRORLEVEL variable for specific values, it is idiomatic (for historical reasons) to check the errorlevel using the following expression
IF ERRORLEVEL 1 ECHO Hello
This will run the given command if ERRORLEVEL is 1 or above - in other words, if any error has occurred.

How do i handle ERRORLEVEL 9 in cmd

I have developed a batch script which checks for the version of the software installed on a machine and based on the version it picks up the correct version patch and installs it (runs) on the machine.
However i am facing an issue where when i check for a particular string in a file path and if the file doesnt exist then it should go to else but in my case it is still continuing with ERRORLEVEL 1 option. Please have a look at the command below:
sfk find "%PATH%\Env\Met\Env.xml" "<Version>806</Version>"
Pause
ECHO %ERRORLEVEL%
Pause
IF ERRORLEVEL 1 (GOTO CHECK_RFA_v8.6) ELSE GOTO CHECK_MET_v8.6
Its possible that some clients based on their subscription may have restricted access to the market and hence few markets could be missing in the software. Here in this case as one of the market is missing, the file Env.xml doesnt exist in the path and so i want it to go to else (CHECK_MET_v8.6) rather than proceed with errorlevel 1 (CHECK_RFA_8.6).
What i dont understand is why is it going to CHECK_RFA_v8.6 if the errorlevel is not 1. I have added ECHO %ERRORLEVEL% to check what is it returning and it is 9.
Output:
Where is software installed?
error: no such file or dir: C:\AR\Env\Met\Env.xml
1 errors occurred.
Press any key to continue . . .
9
Press any key to continue . . .
CHECKING RFA v8.6
Can somebody please explain why would it continue with ERRORLEVEL 1 option if the returned error code is 9? and how can i handle it?
If you read the description of if command (available via if /?), you will realize that if errorlevel number command will execute the command when the errorlevel is greater or equal than the number. If you want to execute the command when the number is precisely a certain value, use this form:
IF %ERRORLEVEL% EQU 1 (GOTO CHECK_RFA_v8.6) ELSE GOTO CHECK_MET_v8.6

Batch File conditional statement not working correctly

So i am attempting to make a simple script to check if an application is running using a external text file (using 1 and 0 for if running or is not). However i cannot seem to get the statement working correctly..
setlocal enabledelayedexpansion
set /p Running=<IsRunning.txt
IF %Running% EQU 0(GOTO ProgramNotRunning)
IF %Running% EQU 1(GOTO ProgramRunning)
:ProgramNotRunning
echo program starting
echo 0 >IsRunning.txt
echo 1 >IsRunning.txt
GOTO:EOF
:ProgramRunning
echo program already running
GOTO:EOF
The issue is no matter what value it is, it always only ever runs the ProgramNotRunning code block and not the other.
Prior to using EQU, i was simply using == to check for equivilance.
Much thanks for any assistance given!
1 - Missing spaces
If %Running% EQU 0 (...
^ This space is needed
2 - In batch files lines of code are executed one after the other unless one command changes this behaviour. You can iterate with for, jump with goto, call subroutines with call, leave the batch, the subroutine or the console with exit, ... but a label will not break the execution. After your if %Running% EQU 1 ... there isn't anything that prevent execution to continue into the code following code it none of the if tests find a coincidence. So, if the set /p does not retrieve 0 or 1 the code after :ProgramNotRunning will be always executed.
3 - Missing/empty file. If IsRunning.txt can not be found or it is empty (or at least the first line is empty) or if it does contain an unexpected value, the if lines will fail. The code executed is
file missing : if EQU 0 (
line/file empty : if EQU 0 (
bad data : if this is a test EQU 0 (
All this cases will cause the line to be considered an error and the execution will be canceled.
#echo off
setlocal enableextensions disabledelayedexpansion
rem Retrieve running state
set "Running="
if exist "IsRunning.txt" (
set /p "Running=" < "IsRunning.txt"
)
IF "%Running%" EQU "0" goto ProgramNotRunning
IF "%Running%" EQU "1" goto ProgramRunning
rem As there is no valid data, assume the program is not running
:ProgramNotRunning
echo program starting
>"IsRunning.txt" (echo 1)
goto :eof
:ProgramRunning
echo program already running
goto :eof
Why >"IsRunning.txt" (echo 1)? Just to be sure there are no aditional spaces after the 1 that will be included in the output (as happens with your code), retrieved when the line is readed from the file and causing the if to fail
if "1 " EQU "1" ( ... This will be evaluated to false
And this still leaves cases where the data retrieved can make the code fail. For a 0/1 test, it is easier to not read the file, just test for presence of the file. If the file exist, the program is running, else it is not running.

Can't get errorlevel from failed MOVE command in batch script

I'm pretty new to this forum so i first want to thank you for providing me with solutions even before i became a member :).
So I have this code:
for %%a in ("%PBpath%") do (
move "network location 1 files" "network location 2" >NUL
if ERRORLEVEL 0 (echo Diagram %%~na.pdf was successfuly archived) else ( echo Diagram %%~na.pdf was not archived )
ECHO.%errorlevel%
)
The problem is that I can't get the errorlevel different than 0. Even when the files that are to be copied are missing from location, i still get the successfuly archived message echoed. I searched the forum for similar questions, but i couldn't make it work for some reason.
Is there something different between the copy and the ping command (the ping command returns the correct exit code in the errorlevel), because i can't get it with either copy or move...
Thanks!
Andrew
The strange thing about the IF ERRORLEVEL statement is that it doesn't act like you expect- it returns TRUE if the errorlevel is equal to OR GREATER THAN the number specified.
A failure in MOVE sets errorlevel to 1 (I just checked) which is greater than 0. Therefore the first clause in the IF statement will always be used. The easiest way to fix your script is to reverse the conditions in the IF statement:
if ERRORLEVEL 1 (echo file was not archived) else (echo file was successfully archived)
Just use %ERRORLEVEL% variable instead of ERRORLEVEL function
If one wants to use the ERRORLEVEL function, Superbob's answer address' this (though I would recommend the form if NOT ERRORLEVEL 1 (echo file was successfully archived) else (echo file was not archived) instead).
But if one wants to use the %ERRORLEVEL% variable method instead, Delayed Expansion needs to be turned on. The OP's code above, with the recommended changes, is below:
setlocal enabledelayedexpansion
for %%a in ("%PBpath%") do (
move "network location 1 files" "network location 2" >NUL
if !ERRORLEVEL! equ 0 (
echo Diagram %%~na.pdf was successfully archived
) else (
echo Diagram %%~na.pdf was not archived)
)

Resources