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 want to get either 0 or 1 from the following reg query:
reg query "hklm\Software\Microsoft\Windows\Currentversion\WindowsUpdate\Auto Update\Rebootrequired"
Instead of getting the Updates or the Error Message, i want to output the Errorcode.
The Problem is, that the whole command must be put in one Line!
Something like "reg query.... 2>&1 | echo %Errorlevel%
Thanks!
Sorry for my bad English!
If you need to do it all on one line then you will need to force delayed expansion to be enabled so that you can echo the errorlevel correctly.
cmd /V:on /C "reg query "hklm\Software\Microsoft\Windows\Currentversion\WindowsUpdate\Auto Update\Rebootrequired" >nul 2>&1 &echo !errorlevel!"
You can also use this.
reg query "hklm\Software\Microsoft\Windows\Currentversion\WindowsUpdate\Auto Update\Rebootrequired" >nul 2>&1 &CALL echo %^errorlevel%
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.
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