Reg QUERY and error handling.. advanced help!

November 30, 2011 at 10:42:33
Specs: Windows XP
Hey guys, this ones a little specific, but I wrote up a script yesterday I seem to be having trouble with. I'm reasonably well experienced with batch and believe I've identified the problem but am unsure of a reasonable workaround.

The aim of the script is essentially:

- Read in a list (file) of registry paths, keys and their values (comma delimited)
- Query the keys in the list for their values and, if it exists, write this information to a custom .reg file containing the keys and their current values (saving the current values in a correctly formatted .reg to re-import later if desired)
- If a key in the list does NOT currently exist, take note of this key by outputting it's path and key name to another file that can be read from later (this is to keep track of NEW keys that my script may add so that if I wish to revert to an original state, I know which new keys were added so I may remove them). THIS IS WHERE MY PROBLEM LIES.
- If desired, there are options for a user to change the values of the listed keys to the values contained within the list file (third comma delimited token), or add the new key with this value if it doesnt exist.
- Can delete any new keys added.


Right now, everything works as desired EXCEPT for my ability to accurately determine the ERRORLEVEL after REG QUERY is run in a FOR loop. It should be simply -- if the key is there, write its value to a custom .reg file. This works fine. If the key does NOT exist, add its path and name to another file ("new_keys.txt") so I can keep track of newly added keys for later removal.

Ive tried to explain this as best I can -- Here are the two files I'm working with -- the batch script and its dependent list file:


--------------------CODE-------------------
@ECHO OFF

REM zRegMod.bat - A simple utility to aid in the backing-up
REM and modification of select registry keys/values per
REM Ziftens needs for customer demos.

SET KEYFILE="keys.txt"
SET REGFILE=Old_Values.reg
SET NEW_KEYS=new_keys.txt

IF /I "%1"=="" (
ECHO.
ECHO zRegMod - A simple utility to aid in the backing-up and
ECHO modification of select registry keys/values per our needs
ECHO for setting up optimized environments. See README.TXT
ECHO for additional information.
ECHO.
ECHO Usage: %~nx0 [-b/-m/-d]
ECHO.
ECHO -b : Backup keys and values defined in %KEYFILE%.
ECHO These keys/values can be restored to their
ECHO backed-up values ^(or removed entirely if it
ECHO is a newly created key^) by executing "%REGFILE%"
ECHO at any time.
ECHO.
ECHO -m : Modifies the value of keys defined in %KEYFILE% to
ECHO reflect the new value defined at the end of each line.
ECHO.
ECHO -d : Deletes any keys/values defined within %KEYFILE% that
ECHO were NOT present on the system before zRegMod was used
ECHO to add them.
ECHO.
ECHO NOTE: To generate a list of keys newly added by
ECHO zRegMod ^(for use with `-d'^), you must first use `-b'.
ECHO This list can be found in %NEW_KEYS%.
ECHO.
GOTO :EOF
)

setLocal enableDelayedExpansion

IF /I "%1"=="-b" (
ECHO.
ECHO [+] Backup up current registry values to %REGFILE%...
ECHO.
ECHO Windows Registry Editor Version 5.00>%REGFILE%
ECHO.>>%REGFILE%

FOR /F "usebackq tokens=1-2 delims=, eol=;" %%A IN (%KEYFILE%) DO (
FOR /F "skip=4 tokens=1-3 delims= " %%C IN ('REG QUERY "%%A" /v %%B') DO (
IF ERRORLEVEL 0 (
ECHO.>>%REGFILE%
IF /I "%%D"=="REG_DWORD" (
ECHO [%%A]>>%REGFILE%
SET DWORD_VAL=%%E
ECHO "%%B"=dword:!DWORD_VAL:~2!>>%REGFILE%
) ELSE (
ECHO [%%A]>>%REGFILE%
ECHO "%%B"="%%E">>%REGFILE%
)
)
IF NOT ERRORLEVEL 0 ECHO %%A,%%B>>%NEW_KEYS%
)
)
ECHO.
ECHO [-] Old registry have been saved to %REGFILE%
ECHO.
GOTO :EOF
)

IF /I "%1"=="-m" (
SET /P APPLY_TWEAKS=[+] Apply registry changes now? (y/n):
IF /I "%APPLY_TWEAKS%"=="n" GOTO :EOF

FOR /F "usebackq tokens=1-3 delims=, eol=;" %%A IN (%KEYFILE%) DO (
ECHO.
ECHO [+] Setting %%B=%%C...
REG ADD "%%A" /v %%B /d %%C /f 1>NUL
)
GOTO :EOF
)

IF /I "%1"=="-d" (
FOR /F "usebackq tokens=1-2 delims=," %%A IN (%NEW_KEYS%) DO (
ECHO.
ECHO [+] Removing newly added key `%%B'...
REG DELETE "%%A" /v %%B
)
GOTO :EOF
)
--------------------CODE-------------------


The line that I'm having issues with is:

--------------------CODE-------------------
IF NOT ERRORLEVEL 0 ECHO %%A,%%B>>%NEW_KEYS%
--------------------CODE-------------------

The list file:

--------------------CODE-------------------
HKEY_CURRENT_USER\Control Panel\Desktop,WaitToKillAppTimeout,1000
HKEY_CURRENT_USER\Control Panel\Desktop,HungAppTimeout,1000
HKEY_CURRENT_USER\.DEFAULT\ControlPanel\Desktop,WaitToKillAppTimeout,1000
HKEY_CURRENT_USER\.DEFAULT\ControlPanel\Desktop,HungAppTimeout,1000
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control,WaitToKillServiceTimeout,1000
HKEY_LOCAL_MACHINE\System\CurrentControlSet1\Control,WaitToKillServiceTimeout,1000
HKEY_LOCAL_MACHINE\System\CurrentControlSet3\Control,WaitToKillServiceTimeout,1000
HKEY_CURRENT_USER\Control Panel\Desktop,MenuShowDelay,200
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced,EnableBalloonTips,0
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Desktop\CleanupWiz,NoRun,1
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib,DisablePerformanceCounters,1
--------------------CODE-------------------

I've tried several different things trying to catch the correct errorlevel at the right time. I've used ERRORLEVEL, %ERRORLEVEL%, !ERRORLEVEL!, moved its position in the loop around, even using double-pipes within the actual REG QUERY to pipe the current ERRORLEVEL into a variable or file that can be read from to get the right errorlevel in real time...

I know Windows is tricky in the way it processes Batch code and has its own less than ideal way of handling things. I assumed this probably had something to do with the ERRORLEVEL being handled by REG.EXE itself and maybe it was still returning 0 in MY code because the code itself was executing without error?...or...something... I don't know.

I just need this thing to spit the keys out to a new file if reg query fails to find it. I hope I haven't been too lengthy with this question... ANY HELP IS APPRECIATED!!!! Thanks :)


See More: Reg QUERY and error handling.. advanced help!

Report •

#1
November 30, 2011 at 14:33:42
I'm probably missing something here, and please forgive me if I am. I only briefly looked at the code... but instead of this:

) ELSE (
ECHO [%%A]>>%REGFILE%
ECHO "%%B"="%%E">>%REGFILE%
)
)
IF NOT ERRORLEVEL 0 ECHO %%A,%%B>>%NEW_KEYS%

couldn't you just put that last line in with all the other 'else' commands like this?

) ELSE (
ECHO [%%A]>>%REGFILE%
ECHO "%%B"="%%E">>%REGFILE%
ECHO %%A,%%B>>%NEW_KEYS%
)
)


Report •

#2
November 30, 2011 at 14:45:15
Thanks for the response :) ... and I wish it were that easy :P

The point of the IF conditional as a whole is to determine, using reg query, whether or not the key exists. If it does exist, I echo it's value out to a .reg script to import later if I want to revert to my previous settings. If it doesn't exist, I want to echo it out to a separate file containing only the keys that were not initially found on the system -- so that I can keep track of new keys I've added myself to the system.

This:

) ELSE (
ECHO [%%A]>>%REGFILE%
ECHO "%%B"="%%E">>%REGFILE%
)
)

...outputs the information I need to the .reg file (after checking to see if its a DWORD and formatting it accordingly)

This:

IF NOT ERRORLEVEL 0 ECHO %%A,%%B>>%NEW_KEYS%

...I assumed, should run in response to the initial REG QUERY is processed in the FOR loop... After the two closing parenthesis. These are two different actions I need taken given a certain ERRORLEVEL.

I've tried various different variations of else, else if, if/if not/blah blah blah.... No luck :(


.....I hate batch. I'd be doing this is something different if it were an option right now...


Report •

#3
November 30, 2011 at 18:01:26
I see now... sorry about that. Have you tried phrasing it like this?

IF %ERRORLEVEL% GTR 0


Report •

Related Solutions

#4
December 1, 2011 at 09:26:17
I have, with no luck :-\ ... The reason I believe it's an issue with error handling at runtime is because even if I simply echo the current error level at that point, it will always return 0 -- UNTIL it comes across a registry key that I know for certain does not exist -- at which point REG.EXE gives it's typical "Error: blah blah key cannot be found" message, and "0" is not echo'd at that time.

For example, my key list contains 11 entries. I know for certain on my current image that all but 2 of these keys exist in my registry. When I run the script having it only echo the errorlevel, it will echo "0" nine times and display the reg.exe error message twice when it tries to query those two keys.

Blehhh


Report •

#5
December 1, 2011 at 11:27:18
Sorry if I'm just repeating all the things you've already tried...

what about:

IF %ERRORLEVEL% NEQ 0


Report •

#6
December 1, 2011 at 12:39:51
No dice.

Report •

#7
December 1, 2011 at 14:21:38
I know we can figure this out. We don't necessarily have to use the errorlevel variable. If the error that comes out of reg.exe always has the same string or part of the same string, we might be able to output all of the zeros and the 2 error messages to a file, and then use findstr to identify that string. Then set and evaluate that custom variable instead of using errorlevel.

So, reg.exe outputs it's findings to file regfound.tmp which might contain:

0
0
0
0
0
0
0
0
Error: blah blah key cannot be found
Error: blah blah key cannot be found

We would use findstr and an && (command upon success) in a for loop to set the variable like this:

findstr /i "key cannot be found" c:\regfound.tmp && set manerrlevel=1

Now you can evaluate manerrlevel

Does that make sense?


Report •

Ask Question