Reputation: 35
My batch file runs several registry edit commands, and I want to implement a conditional if said registry edit commands return error levels. My question is: should I wrap these commands in a function, or create the error levels conditional after EVERY registry command? My concern regarding wrapping these commands into a function is that not every command will get checked. I want to ensure that each command gets checked, and returns an error level.
The code chunk for wrapping the commands in a function could be incorrect or missing pieces. Not sure if I need to include an EXIT at the conclusion of each function? This is apart of a multi-step batch script.
TITLE Disable UAC
ECHO STEP 1: Disable User Account Control
reg add HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f
IF %ERRORLEVEL% NEQ 0 ECHO An error was found w/ error code of: %ERRORLEVEL%
or
:disable_uac
TITLE Disable UAC
ECHO STEP 1: Disable User Account Control
reg add HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f
call :disable_uac
IF %ERRORLEVEL% NEQ 0 ECHO An error was found w/ error code of: %ERRORLEVEL$
Regarding the first code chunk, I assume that the ERRORLEVEL conditional is only going to return the error code of the LAST command rather than the both?
Updated Code:
@echo off
goto ErrorCheck
SetLocal EnableDelayedExpansion
ECHO STEP 1: Copy Folder
robocopy "C:\Users\!username!\Documents\WindowsSetup\Training_Videos" "C:\Users\!username!\Desktop\Training_Videos" /e /copyall
CMD /K
:ErrorCheck
title Disable UAC
for /F "useback skip=2 delims= eol=" %%I in ("%~f0") do (
IF "%%~I" == ":ErrorCheck" exit /B
ECHO %%I
%%I >>"C:\errorlog.log"
if errorlevel 1 exit /B & ECHO You have encountered an issue. Look at Error Log for more information
)
Upvotes: 2
Views: 4594
Reputation: 49086
A very simple solution to run multiple commands written in a batch file with suppressing standard output written to handle STDOUT and error messages written to handle STDERR with exiting batch file execution on first command or executable exiting with an exit code greater or equal 1
is:
@echo off
goto MainCode
reg.exe add HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f
reg.exe add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f
:MainCode
title Disable UAC
for /F "useback skip=2 delims= eol=" %%I in ("%~f0") do (
if "%%~I" == ":MainCode" exit /B
echo %%I
%%I >nul 2>nul
if errorlevel 1 exit /B
)
This batch file executes all non-empty lines defined in the batch file below second line because of skip=2
on FOR loop command line and the label line :MainCode
.
These command lines cannot contain environment variable references with the code as provided because of the environment variable references would not be expanded by Windows command processor before execution. It is of course possible to use command call
to force an additional parsing of a command line during FOR loop execution to expanded environment variable references.
The command lines between goto MainCode
and :MainCode
also cannot contain redirection operators like <
, >
, >>
and |
. The redirections are done by cmd.exe
executing the batch file. Windows command processor must recognize them already on parsing the command line before execution. So when cmd.exe
parses the command line %%I >nul 2>nul
before execution, it recognizes the redirections >nul
and 2>nul
before execution of whatever is currently assigned to loop variable I
, but cmd.exe
will never recognize such redirections specified on command line assigned to loop variable I
.
See also How does the Windows Command Interpreter (CMD.EXE) parse scripts?
The execution of this demonstration batch file is exited immediately on first command/executable exiting with a value greater or equal 1
. The commands IF and EXIT don't modify variable errorlevel
and so the calling process gets the exit code of the failed command/executable.
See also:
The exit code of the batch file is 0
on no command exits with a value greater or equal 1
.
FOR opens here the batch file already executed by cmd.exe
specified with %~f0
which expands to drive + path + name + extension of the batch file itself because of option /F
and processes it line by line.
The option usebackq
is necessary to get the full batch file name enclosed in "
interpreted as file name of which lines should be processed instead of interpreting the full qualified batch file name itself as string to process by FOR.
The option skip=2
tells FOR to skip the first two lines of the opened file and start processing the lines with third line.
FOR with option /F
ignores always empty lines. Lines starting with a semicolon are ignored also by FOR on usage of option /F
because of eol=;
is the default end of line definition. For that reason eol=
is used to define no end of line character resulting in not ignoring lines starting with a semicolon.
FOR splits up by default every non-empty line read from file into substrings using normal space and horizontal tab as string delimiters and would assign only first space/tab delimited string to specified loop variable I
. This line splitting behavior is not wanted here. The entire line as written in the batch file should be assigned to loop variable I
. For that reason delims=
is specified to define an empty list of string delimiting characters which disables line splitting behavior completely.
The main code of the batch file could be also written as follows:
title Disable UAC
del "%TEMP%\%~n0.log" 2>nul
for /F "useback skip=2 delims= eol=" %%I in ("%~f0") do (
if "%%~I" == ":MainCode" goto Finished
%%I >nul 2>>"%TEMP%\%~n0.log" || exit /B
)
:Finished
del "%TEMP%\%~n0.log" 2>nul
exit /B 0
This variant of the batch file runs the commands/executables silently with suppressing standard output and logging error output into a file in folder for temporary files with name of batch file with file extension .log
.
The loop is exited if any command/executable exits with a value not equal 0 with the exit code of last executed command/executable or on reaching label line with deletion of the empty log file and exit code 0.
And even more enhanced version is:
@echo off
goto MainCode
e TITLE Disable UAC
c echo Errors are log into file: "%TEMP%\%~n0.log"
p STEP 1: Disable User Account Control
r reg.exe add HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f
r reg.exe add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f
:MainCode
del "%TEMP%\%~n0.log" 2>nul
for /F "useback skip=2 tokens=1* eol=" %%I in ("%~f0") do (
if %%I == :MainCode del "%TEMP%\%~n0.log" 2>nul & exit /B 0
if %%I == c (
call %%J
) else if %%I == e (
%%J
) else if %%I == p (
echo(%%J
) else (
%%J >nul 2>>"%TEMP%\%~n0.log" || exit /B
)
)
There is a single character at beginning of each command line to execute in FOR loop controlling how to execute this line. The character is separated from the command line with one or more spaces or a horizontal tab character. The meaning of the execution control characters is as follows:
0
indicating a not successful execution.The (
between echo
and %%J
makes it possible to print also a blank line by inserting in command block a line with just p
.
The FOR option delims=
is replaced by tokens=1*
. The line splitting behavior of FOR with the default delimiters space and tab is wanted here. The first space/tab delimited string should be assigned to loop variable I
which is here the command execution controlling character at beginning of each line to execute or output respectively the label :MainCode
. Everything after spaces/tabs after first string assigned to loop variable I
should be not split up further on spaces/tabs. For that reason *
is appended to tokens=1
which tells FOR to assign the rest of the line after the spaces/tabs after c
, e
, p
or r
to next loop variable according to the ASCII table which is the character J
.
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 %~f0
... full file name of argument 0, i.e. batch file name with file extension and with full path as well as %~n0
which expands to just file name of batch file without file extension and path.echo /?
exit /?
for /?
goto /?
if /?
... explains that if ERRORLEVEL number
means if ERRORLEVEL
is greater or equal number
and not equal number
as many people not reading help/documentation think.reg /?
reg add /?
See also single line with multiple commands using Windows batch file for an explanation of the operators &
and ||
.
Upvotes: 1
Reputation: 124696
I'd do it using conditional execution, e.g.:
@echo off
CALL :DISABLEUAC || GOTO :ERRHANDLER
GOTO :EOF
:DISABLEUAC
ECHO STEP 1: Disable User Account Control
reg add HKEY_CURRENT_USER\... /f || GOTO :EOF
reg add HKEY_LOCAL_MACHINE\... /f || GOTO :EOF
GOTO :EOF
:ERRHANDLER
ECHO An error was found w/ error code of: %ERRORLEVEL%
GOTO :EOF
Within the DISABLEUAC subroutine, use conditional execution to exit the subroutine if a command fails
In the main module, call the subroutine and use conditional execution to jump to an error handler if the subroutine fails.
Upvotes: 0