I want to check if a certain registry key exists and if so, check its value as well
if it equals 0 (for example), then write to log: not found
if it equals 1 (for example), then write to log: found
should I stick to reg query and if structure or is there an easier method?
How do I check if a key is present in the windows registry
This can be done using reg query key:
This command will set %errorlevel%.
errorlevel=0 means the key exists.
errorlevel=1 means the key does not exist.
Example batch file
#echo off
Set mykey="HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"^
^ "HKCU\Software\Microsoft\Windows\CurrentVersion\Run"^
^ "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"^
^ "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices"^
^ "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices"^
^ "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options"^
^ "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"^
^ "HKEY_LOCAL_MACHINE\SOFTWARE\Hackoo"
Set LogFile=logkey.txt
If Exist %LogFile% Del %LogFile%
For %%K in (%mykey%) Do Call :Check_Key %%K %LogFile%
Start "" %LogFile%
Exit /b
:Check_Key
reg QUERY %1 >nul 2>&1
(
if %errorlevel% equ 0 ( echo %1 ===^> Found && reg QUERY %1
) else ( echo %1 ===^> Not found
)
) >>%2 2>&1
Further reading
reg - Read, Set or Delete registry keys and values, save and restore from a .REG file.
An A-Z Index of the Windows CMD command line is an excellent reference for all things Windows cmd line related.
Unfortunately, I haven't found a proper way to check if the value is actually correct. You can use a FOR loop and tokens= to locate the value and compare but what happens when the REG QUERY returns more tokens than you're expecting? Using FIND fails in both a simple REG QUERY | FIND and in the FOR loop because it always returns the wrong %ERRORLEVEL% beyond one level. Even with DelayedExpansion, it seems it will eventually fail.
Related
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
REG ADD changes the entire entry. I have not been able to make REG ADD ~ work.
Windows registry contains multiple string zero values. This is what REG_MULTI_SZ means. How can a new string be appended? REG ADD deletes all string previously in the entry and writes only the new one there although REG_MULTI_SZ is specified in the REG ADD command.
Some say ~ before the string means append instead of overwrite. However, I do not what the exact syntax is. How can I use ~?
[Edit]Here is the simplified version of the question :
I have a registry entry KEYROOT\KEY\ENTRY which is type REG_MULTI_SZ. In this entry, there are string zeroes abcd\0 and efgh\0. How can I add ijkl\0 in order to have all three: abcd, efgh and ijkl in the registry entry \ENTRY and not only ijkl?
I want to do this only with Batch Script or Command Prompt commands.
Please, note : I have tried many things with REG and am unable to find a solution and I am not sure whether there is such.
I will be very thankful for any suggestions but I would like to ask you all to concentrate on the ~ possibility. Microsoft says when there is ~ before the string, the string is considered to be appended to the other strings and not to overwrite them.
I have tried many variations but am unable to get the correct syntax of ~. Please, do provide information on how to use ~ before the string to be appended.
I found a solution. However, although the solution works, to add a string to the registry entry is not a good idea because Microsoft allows strings to be appended with hex data. Anyway, here is what I have been able to do :
Read the value of the registry in a batch string variable :
FOR /F "usebackq tokens=2,* skip=2" %%G IN ('REG QUERY "Root\Key" /v Entry') DO SET EntryContents=%%H
Note the reverse apostrophes `.
Now, the entry of the registry key is in the variable EntryContents.
Concatenate the new value to the old value
SET NewEntryContents=%EntryContents%%ContentsToBeAppended%
The variable ContentsToBeAppended has been set elsewhere in the batch file or may be a parameter. The variable NewEntryContents contains the concatenated strings of the old registry key entry contents and the string which is in the variable ContentsToBeApended.
Add NewEntryContents to the entry with REG ADD.
Again, when the entry value is read into a string variable, all hex contents would be ignored in case they are 00's or other values which may be out of the character range. A solution may be to somehow export the entry with REG to a file in hex format and then to somehow add only hex values to the file. The string characters must be converted to their hex values and appended to the file as well as any new hex values.
This answer provides the ability to read a registry entry which would be read in full with all characters such as \0 in a string variable. The string variable will get all characters. Example : In case the registry entry contains PATH\NAME_OF_FILE\0PATH|NAME_OF_FILE, all these will be read into the string variable. \0 too. Just concatenate the new string, which may also contain\0's, and reg add the overall string back to the registry.
The trick here is the for /f statement which skips 2 lines and takes the second string of the third line in G and the third ( the important one ) in H. All blanks and *'s, .'s, dits will be read too.
In order to add all blanks and *'s etcetera back to the entry with reg add, enclose the variable NewEntryContents in quotes :
REG ADD "Root\Key" /v Entry /t REG_MULTI_SZ /d "%NewEntryContents%"
Hope this may help.
Also, the [~] sign works only when REGEDIT is used. REGEDIT is a better approach. Can save a key as is ( with hex ) in a file, then the file can be edited in the batch and then the newly edited key can be imported back to the registry. Pretty nasty, though. Also, I am not sure whether REGEDIT would export the strings and the hex data combined to the file.
Here are the checks for the availability of the entry and for an empty entry :
This checks whether the entry is there or not at all :
REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager" /v PendingFileRenameOperations
IF %ERRORLEVEL% EQU 0 GOTO THEREIS
After the for /f :
SET "EntryContents"="%EntryContents: =%" IF DEFINED EntryContents GOTO NOTEMPTY
The SET line is not necessary. Gets rid of blanks around the string. This is supposed to be done by the for /f anyway.
If defined checks the value. Best EntryContents never to have been defined before the for /f.
OK. I have managed to overcome all problems with batch script only.
Echo does echo all ASCII characters and can be made to output Unicode too, however, there are many more problems.
Anyway, I am unable to provide more information because of the amount of problems and solutions BUT, whoever is interested, can read the batch file I have made : http://www.steven-stanley-bayes.com/ForceDelete.zip
Lean and mean batch-file alternative to the ~50KB script linked by OP:
~ Accepting a single parameter, either File or Folder
~ Confirmation prompt ([Cancel] to Clear previous entries)
~ Basic idiot proofing (don't process %Windir% for example)
~ Scripts will add an entry to right-click -- "SendTo" menu on first run
Rename_On_Boot.bat
goto="Batch" /* Rename_On_Boot by AveYo v1
:RenOnBoot
set "input=%*" & call set "input=%%input:?=%%" &rem line below adds entry to right-click -- "SendTo" menu
if /i "_%~dp0"=="_%APPDATA%\Microsoft\Windows\SendTo\" (set .=) else copy /y "%~f0" "%APPDATA%\Microsoft\Windows\SendTo\" >nul 2>nul
if "_%1"=="_" color 4f & echo ERROR! No input provided & ping -n 6 localhost >nul & exit /b
for %%# in ("C:\" "C:\Boot" "C:\Recovery" "%WINDIR%" "%WINDIR%\system32" "%ProgramData%" "%ProgramFiles%" "%USERPROFILE%") do (
if /i "_%input%"=="_%%~#" color 4f & echo ERROR! %%# is not safe to delete & ping -n 6 localhost >nul & exit /b
)
color 0B & echo Please wait, folders might take a while .. & call cscript /nologo /e:JScript "%~f0" RenOnBoot "%input%" & exit /b
:RenOnBoot_Run_As_Admin
color 4f & echo Asking permission to run as Admin.. & call cscript /nologo /e:JScript "%~f0" RunAsAdmin "%~f1???" & exit /b
:"Batch"
#echo off & setlocal disabledelayedexpansion & mode 96,4 & echo. & title %~nx0 by AveYo & if not exist "%~f1" goto :RenOnBoot
reg query HKEY_USERS\S-1-5-20\Environment /v temp 1>nul 2>nul && goto :RenOnBoot || goto :RenOnBoot_Run_As_Admin
:"JScript" */
function RenOnBoot(f){
var HKLM=0x80000002, k='SYSTEM\\CurrentControlSet\\Control\\Session Manager', v='PendingFileRenameOperations';
var reg=GetObject('winmgmts:{impersonationLevel=impersonate}!//./root/default:StdRegProv'), ws=WSH.CreateObject('WScript.Shell');
var confirmation=ws.Popup(" Rename on next boot? [OK]\n Clear previous entries? [Cancel]\n\n "+f,0,'Rename_On_Boot by AveYo',33);
if (confirmation == 2) { reg.DeleteValue(HKLM, k, v); WSH.quit(); } // Clear existing entries on Cancel press and quit script
var mtd=reg.Methods_('GetMultiStringValue').InParameters.SpawnInstance_(); mtd.hDefKey=HKLM; mtd.sSubKeyName=k; mtd.sValueName=v;
var query=reg.ExecMethod_('GetMultiStringValue', mtd), regvalue=(!query.ReturnValue) ? query.SValue.toArray():[,], entries=[];
var fso=new ActiveXObject('Scripting.FileSystemObject'), fn=fso.GetAbsolutePathName(f);
entries.push('\\??\\'+fn,'\\??\\'+fn+'.ren');
reg.CreateKey(HKLM, k); reg.SetMultiStringValue(HKLM, k, v, entries.concat(regvalue));
}
if (WSH.Arguments.length>=2 && WSH.Arguments(0)=='RenOnBoot') RenOnBoot(WSH.Arguments(1));
function RunAsAdmin(self, arguments) { WSH.CreateObject('Shell.Application').ShellExecute(self, arguments, '', 'runas', 1) }
if (WSH.Arguments.length>=1 && WSH.Arguments(0)=='RunAsAdmin') RunAsAdmin(WSH.ScriptFullName, WSH.Arguments(1));
//
Delete_On_Boot.bat
goto="Batch" /* Delete_On_Boot by AveYo v1
:DelOnBoot
set "input=%*" & call set "input=%%input:?=%%" &rem line below adds entry to right-click -- "SendTo" menu
if /i "_%~dp0"=="_%APPDATA%\Microsoft\Windows\SendTo\" (set .=) else copy /y "%~f0" "%APPDATA%\Microsoft\Windows\SendTo\" >nul 2>nul
if "_%1"=="_" color 4f & echo ERROR! No input provided & ping -n 6 localhost >nul & exit /b
for %%# in ("C:\" "C:\Boot" "C:\Recovery" "%WINDIR%" "%WINDIR%\system32" "%ProgramData%" "%ProgramFiles%" "%USERPROFILE%") do (
if /i "_%input%"=="_%%~#" color 4f & echo ERROR! %%# is not safe to delete & ping -n 6 localhost >nul & exit /b
)
color 0B & echo Please wait, folders might take a while .. & call cscript /nologo /e:JScript "%~f0" DelOnBoot "%input%" & exit /b
:DelOnBoot_Run_As_Admin
color 4f & echo Asking permission to run as Admin.. & call cscript /nologo /e:JScript "%~f0" RunAsAdmin "%~f1???" & exit /b
:"Batch"
#echo off & setlocal disabledelayedexpansion & mode 96,4 & echo. & title %~nx0 by AveYo & if not exist "%~f1" goto :DelOnBoot
reg query HKEY_USERS\S-1-5-20\Environment /v temp 1>nul 2>nul && goto :DelOnBoot || goto :DelOnBoot_Run_As_Admin
:"JScript" */
function DelOnBoot(f){
ListDir=function(src, _root,_list) {
_root=_root || src, _list=_list || [];
var root=fso.GetFolder(src), files=new Enumerator(root.Files), dirs=new Enumerator(root.SubFolders);
while (!files.atEnd()) { _list.push(files.item()); files.moveNext(); }
while (!dirs.atEnd()) { _list=ListDir(dirs.item().path, _root,_list); _list.push(dirs.item()); dirs.moveNext(); }
return _list;
};
var HKLM=0x80000002, k='SYSTEM\\CurrentControlSet\\Control\\Session Manager', v='PendingFileRenameOperations';
var reg=GetObject('winmgmts:{impersonationLevel=impersonate}!//./root/default:StdRegProv'), ws=WSH.CreateObject('WScript.Shell');
var confirmation=ws.Popup(" Delete on next boot? [OK]\n Clear previous entries? [Cancel]\n\n "+f,0,'Delete_On_Boot by AveYo',33);
if (confirmation == 2) { reg.DeleteValue(HKLM, k, v); WSH.quit(); } // Clear existing entries on Cancel press and quit script
var mtd=reg.Methods_('GetMultiStringValue').InParameters.SpawnInstance_(); mtd.hDefKey=HKLM; mtd.sSubKeyName=k; mtd.sValueName=v;
var query=reg.ExecMethod_('GetMultiStringValue', mtd), regvalue=(!query.ReturnValue) ? query.SValue.toArray():[,], entries=[];
var fso=new ActiveXObject('Scripting.FileSystemObject'), fn=fso.GetAbsolutePathName(f);
if (fso.FolderExists(fn)) { var list=ListDir(fn); for (var i in list) entries.push('\\??\\'+list[i],''); }
entries.push('\\??\\'+fn,'');
reg.CreateKey(HKLM, k); reg.SetMultiStringValue(HKLM, k, v, entries.concat(regvalue));
}
if (WSH.Arguments.length>=2 && WSH.Arguments(0)=='DelOnBoot') DelOnBoot(WSH.Arguments(1));
function RunAsAdmin(self, arguments) { WSH.CreateObject('Shell.Application').ShellExecute(self, arguments, '', 'runas', 1) }
if (WSH.Arguments.length>=1 && WSH.Arguments(0)=='RunAsAdmin') RunAsAdmin(WSH.ScriptFullName, WSH.Arguments(1));
//
Although not requested, you could probably use something like this in PowerShell:
$key = Get-Item "KEYROOT:\KEY\"
$values = $key.GetValue("ENTRY")
$values += "ijkl"
Set-ItemProperty "KEYROOT:\KEY\" "ENTRY" $values -Type MultiString
Change KEYROOT, KEY & ENTRY to their genuine strings
The following batchfile does the job in four steps:
export the value into a file,
extract the value using the for command
in the subroutine
if the value is valid, concat the string and
finally write the value back.
In this code, HKCU\Software\AITEM is the registry key and AVALUE is the Name of the value. Finally "newstring" is the string you want to add to your list.
The echo command is just for debugging purposes an can be deleted.
The code only works if the key AITEM and the value AVALUE already exist and if AVALUE already has at least one string in its list.
#echo off
reg query HKCU\Software\AITEM /v AVALUE > tmp.txt
FOR /F "tokens=2,3*" %%a in (tmp.txt) do call :sub1 %%b
del tmp.txt
:sub1
if %1x==x goto end
echo %1
REG ADD HKCU\Software\AITEM /f /v AVALUE /t REG_MULTI_SZ /d %1\0newstring
:end
goto :eof
The following code also works if AVALUE does not exist or is empty:
#echo off
reg query HKCU\Software\AITEM /v AVALUE > tmp.txt
find "AVALUE" tmp.txt
if errorlevel 1 goto sub2
FOR /F "tokens=2,3*" %%a in (tmp.txt) do call :sub1 %%b
del tmp.txt
goto :eof
:sub2
REG ADD HKCU\Software\AITEM /f /v AVALUE /t REG_MULTI_SZ /d newstring
goto :eof
:sub1
REG ADD HKCU\Software\AITEM /f /v AVALUE /t REG_MULTI_SZ /d %1\0newstring
if errorlevel 1 REG ADD HKCU\Software\AITEM /f /v AVALUE /t REG_MULTI_SZ /d newstring
goto :eof
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.
I have the following line in a batch script
for %%a in (*.rmt) do (findstr /C:" model='" %%a)>tmp.par
When I run this on an empty folder, the errorlevel is still 0.
However, if I replace *.rmt with a filename, say x.rmt, which doesnt exist in the folder either, the errorlevel becomes 1.
Ideally, if there are no RMT files in the folder, shouldnt the errorlevel!=0?
I require this For loop to work on *.rmt, as there might be 0 to multiple RMT files in a folder. Please help.
Thanks.
Note: If the string " model='" exists in one RMT file, it will compulsorily be present in all the other RMT files(if any) in the folder.
The findstr is never executed if there are no matches to the *.rmt, hence the errorlevel remains unchanged.
When you use x.rmt, FOR changes behaviour - it's no longer looking for a filename matching, it's looking at a particular string - which may or may not be a filename, which may or may not exist.
You could deliberately set errorlevel before the for
#ECHO OFF
SETLOCAL
ECHO y|FIND "x">nul
for %%a in (*.rmt) do (findstr /C:" model='" %%a)
ECHO errorlevel=%errorlevel%
GOTO :EOF
which will return errorlevel 1 unless the match is found.
Try this:
#echo off
for /F "delims=" %%i in ('dir /b "path_to_dir\*.rmt"') do (
:: echo Folder is NON empty
findstr /C:"model='" %%i >> C:\testlog.log
goto :EOF
)
No, the FOR command never sets the ERRORLEVEL <> 0 if there are no iterations.
Yes, the following command reports ERRORLEVEL=1:
for %%a in (notExists.rmt) do (findstr /C:" model='" %%a)>tmp.par
But that is because the simple FOR simply lists the string(s) within the IN() clause if they do not contain wildcards. It doesn't bother checking to see if the file exists. So your FINDSTR command is actually raising the error because it cannot find the file, not the FOR statement.
Your command is flawed in that each iteration overwrites the previous tmp.par. That can be easily fixed by adding an extra level of parentheses. This also will create an empty tmp.par if no files were found or if none of the files contained the search string. The ERRORLEVEL cannot be relied upon because its value will not have been set if no files were found, or it may be 0 or 1 depending on if the last file contained the search string.
(for %%a in (*.rmt) do (findstr /C:" model='" %%a))>tmp.par
If you don't mind having a filename: prefix on each line of output, then you can simplify your code to:
findstr /C:" model='" *.rmt >tmp.par 2>nul
This also will create an empty tmp.par file if no files were found, or if none of the files contain the search string. But now the ERRORLEVEL will be reliable. The ERRORLEVEL is 1 if no files are found or if no files contain the search string. Otherwise the ERRORLEVEL will be 0.
I'm looking for a quick and easy way (I don't need any error checking) to switch between two reg files by opening a batch file.
If a user runs a batch file, the batch file should merge reg file A to the registry. If the user runs it again, the batch file should merge reg file B to the registry. If the user runs it again, file A is merged... you get the point.
In general, I think there are two ways to do this:
Create some sort of variable to store which reg should be run next.
Check the registry key values to see which reg has been merged most recently (probably the preferred method).
Currently, I'm doing this:
REG QUERY "KeyName" /v "ValueName" | Find "x"
IF ERRORLEVEL 1 regedit /S file1.reg
IF ERRORLEVEL 0 regedit /S file2.reg
The REG QUERY part seems to work, but at the IF ERRORLEVEL statements something is going wrong. But maybe I should use a different method altogether.
Hoping for some suggestions.. Thanks in advance!
EDIT
Sorry for being a bit vague: I believe the previous solution didn't work, because when the first IF is correct, the second IF will be too after the first IF's command. So I will need an IF ELSE statement to prevent running the second IF.
I've now come up with this solution, which works:
REG QUERY "KeyName" /v "ValueName" | Find "x
IF ERRORLEVEL 1 (REGEDIT /S "file1.reg") ELSE REGEDIT /S "file2.reg"
I was also wondering: would it be an improvement to have the registry key/values added inside the batch file instead of using seperate .reg files? The value types are REG_BINARY and REG_DWORD.
I would try this:
REG QUERY "KeyName" /v "ValueName" | Find "x"
IF ERRORLEVEL 1 (
regedit /S file1.reg
goto :EOF
)
regedit /S file2.reg
The IF condition is set to TRUE when the ERRORLEVEL is equal to, or greater than, the ERRORLEVEL number (see here: http://support.microsoft.com/kb/39585/en-us) so the second IF condition is always evaluated as true.
You can store a value in a enviroment variable
#Echo OFF
:: By Elektro H#cker
Set | FIND "Merged" >NUL && Regedit /S "File_B.reg" || Regedit /S "File_A.reg" && SETX Merged YES >NUL
Pause&Exit
This is the same code but indented and with a quickly explanation:
#Echo OFF
:: By Elektro H#cker
REM If it's batfile first launch then I add a value "YES" to a variable and then only merges the File A.
REM If isn't batfile first launch then only merges FILE B
Set | FIND "Merged" >NUL && (
Regedit /S "File_B.reg"
) || Regedit /S "File_A.reg" && (
SETX Merged YES >NUL
)
Pause&Exit