Windows batch file to block multiple hosts (using list) - windows

I want to add multiple lines to the hosts file if they're not existing. My code works great but I want to do it for a list of 30 entries and thats where I don't know how to handle it. I thought about a list and a for-loop but I don't know how.
#ECHO OFF
ECHO Checking administrator right.
OPENFILES >NUL 2>&1
IF %ERRORLEVEL% EQU 0 (
ECHO Administrator right detected.
ECHO.
ECHO Hosts file : %WINDIR%\system32\drivers\etc\hosts
ECHO.
SETLOCAL ENABLEDELAYEDEXPANSION
SET BLOCKLINE=127.0.0.1 example.com
ECHO Checking : !BLOCKLINE!
FIND /C /I "!BLOCKLINE!" "%WINDIR%\system32\drivers\etc\hosts" >NUL 2>NUL
IF !ERRORLEVEL! NEQ 0 (
ECHO Line not found, adding to the hosts file.
ECHO !BLOCKLINE!>>%WINDIR%\system32\drivers\etc\hosts
) ELSE (
ECHO Line found.
)
ECHO.
ENDLOCAL
ECHO Patching is completed.
ECHO Check hosts file if you want to see the result.
ECHO.
) ELSE (
ECHO Administrator right not detected.
ECHO You need admin right to use this hosts patch!
ECHO.
)
PAUSE

A basic for loop will suffice.
Define the lines to test in the loop set
For %%L in (
"127.0.0.1 example1"
"127.0.0.30 example30"
) Do (
ECHO Checking : %%~L
FIND /C /I "%%~L" "%WINDIR%\system32\drivers\etc\hosts" >NUL 2>NUL
IF !ERRORLEVEL! NEQ 0 (
ECHO Line not found, adding to the hosts file.
>>"%WINDIR%\system32\drivers\etc\hosts" ECHO %%~L
) ELSE (
ECHO Line found.
)
)

Related

Batch File Resume with Prewritten Arguments

I have two batch files one batch files calls another. The one that calls the other is called install.bat, and the other controller.bat.
The contents of install.bat are as follows:
start controller.bat a.exe b.exe
Then the controller.bat file operates as such:
#echo off
:: Check if the first argument is passed
if "%~1"=="" (
echo "No first argument passed"
) else (
set first_arg=%~1
)
:: Check if the second argument is passed
if "%~2"=="" (
echo "No second argument passed"
) else (
set second_arg=%~2
if not "%~1" == "" (
set current=one
) else(
echo twob >%~dp0current.txt
)
)
call :Resume
goto %current%
goto :eof
:one
::Add script to Run key
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v %~n0 /d %~dpnx0 /f
echo two >%~dp0current.txt
echo -- Section one --
echo "update will start"
start /wait %second_arg%
echo "update done"
pause
shutdown -r -t 0
goto :eof
:two
echo three >%~dp0current.txt
echo -- Section two --
echo "updating now"
Start /wait %first_arg%
echo "Update Finish"
pause
shutdown -r -t 0
goto :eof
:twob
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v %~n0 /d %~dpnx0 /f
echo three >%~dp0current.txt
echo -- Section two --
echo "updating now"
Start /wait %first_arg%
echo "Update Finish"
pause
shutdown -r -t 0
goto :eof
:three
::Remove script from Run key
reg delete HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v %~n0 /f
del %~dp0current.txt
echo -- Section three --
pause
goto :eof
:resume
if exist %~dp0current.txt (
set /p current=<%~dp0current.txt
) else (
set current=one
)
The problem it is not working well it jumps into twob and then straight to three. It is supposed to show the intermediate steps to a user to show the updates are occurring.
I am expecting it to be able to read if one argument is supplied let's say the second and not the first and still do the jumps to right labels. Right now, the labels are a bit mixed up when I supply both args %~1 and %~2.

Modify a specific setting in an INI file on multiple PCs using Windows Batch

My goal is to modify a single setting in an INI file over the network on multiple PC's using an external list of PCs, and output the results to a log file.
Needs to be a windows batch file. Network is locked out of running scripts such as PS.
Security is not an issue, as read\write access is open at my level to all targeted PCs.
The content of the INI file to be modified, is unique to the PC, so blanket overwrite/copy is not an option.
The removal or addition of blank lines in the INI is not an issue.
The file PCList.txt, could contain 1-100 PC names or IP's, one per line.
Output to a log file with PCNAME: 'Success' or 'Fail'
So far, I have found and modified a script that will edit a file locally, but have been unable to get it to work with a FOR/DO loop to process that action for each PC in the list - OR - add the logging output
#Echo Off
SetLocal EnableDelayedExpansion
Set _PathtoFile=C:\Test\Sample.ini
Set _OldLine=Reboot=
Set _NewLine=Reboot=1
Call :_Parse "%_PathtoFile%"
Set _Len=0
Set _Str=%_OldLine%
Set _Str=%_Str:"=.%987654321
:_Loop
If NOT "%_Str:~18%"=="" Set _Str=%_Str:~9%& Set /A _Len+=9& Goto _Loop
Set _Num=%_Str:~9,1%
Set /A _Len=_Len+_Num
PushD %_FilePath%
If Exist %_FileName%.new Del %_FileName%.new
If Exist %_FileName%.old Del %_FileName%.old
Set _LineNo=0
For /F "Tokens=* Eol=" %%I In (%_FileName%%_FileExt%) Do (
Set _tmp=%%I
Set /A _LineNo+=1
If /I "!_tmp:~0,%_Len%!"=="%_OldLine%" (
>>%_FileName%.new Echo %_NewLine%
) Else (
If !_LineNo! GTR 1 If "!_tmp:~0,1!"=="[" Echo.>>%_FileName%.new
SetLocal DisableDelayedExpansion
>>%_FileName%.new Echo %%I
EndLocal
))
Ren %_FileName%%_FileExt% %_FileName%.old
Ren %_FileName%.new %_FileName%.ini
PopD
Goto :EOF
:_Parse
Set _FilePath=%~dp1
Set _FileName=%~n1
Set _FileExt=%~x1
Goto :EOF
Here is the sample files: Settings.ini
[SAMPLE SETTINGS]
SERVER=MYPC
Reboot=0
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
PCList.txt
MY-PC
YOUR_PC
NETSERVER
192.168.10.100
Still trying to wrap my head around everything that this script is doing - this was the only information provided in the tech's answer (source of the initial script)
It preserves the original file by renaming it with a .old extension
It will remove all blank lines, but will insert a blank line before any line that starts with [ (unless it's the first line in the file)
I get the length of the specified search line in case the old line in the file has trailing spaces.
If more than one line starts with the old line text, it will be changed as well. Example, if the file has these lines: test=line1 test=line1 again and you set _OldLine to test=line1, both lines will be changed.
If that might be a problem,
change this line: If /I "!_tmp:~0,%_Len%!"=="%_OldLine%" (
to this: If /I "!_tmp!"=="%_OldLine%" (
Just keep in mind that with this, if the old line in the file has trailing spaces, it won't be changed unless you include them in the _OldLine variable
The main thing I need at this point is getting this action to take place using the above script... Or something similar, on a list of PC's listed in an external TXT file - over the network. I'm open to alternative approaches provided they are windows batch scripting, and do not include calling an external application.
Wish list, (by no means required at this time):
Ability to specify or set the [SECTION] in the INI where the setting being modified is found, some potential for the same setting to be found in multiple sections within the same INI (not the case with my initial needs, but I can see it being the case in the future)
Batch file code for the task
I suggest to use the following code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SectionName=[SAMPLE SETTINGS]"
set "EntryName=Reboot"
set "EntryValue=1"
set "LogFile=%~dpn0.log"
set "TempFile=%TEMP%\%~n0.tmp"
set "ListFile=%~dp0PCList.txt"
if not exist "%ListFile%" (
echo ERROR: List file %ListFile%" not found.>"%LogFile%"
goto EndBatch
)
del /A /F "%LogFile%" 2>nul
for /F "usebackq delims=" %%I in ("%ListFile%") do call :UpateIniFile "\\%%I\C$\Test\Sample.ini"
goto EndBatch
:UpateIniFile
if not exist %1 (
echo File not found: %1>>"%LogFile%"
goto :EOF
)
set "EmptyLines="
set "EntryUpdate="
set "CopyLines="
(for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" %1 2^>nul') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
if defined CopyLines (
echo(!Line:*:=!
endlocal
) else if not defined EntryUpdate (
echo(!Line:*:=!
if /I "!Line:*:=!" == "!SectionName!" (
endlocal
set "EntryUpdate=1"
)
) else (
if /I "!Line:*:=!" == "!EntryName!=!EntryValue!" (
endlocal
goto ValueExists
)
if "!Line:*:=!" == "" (
endlocal
set /A EmptyLines+=1
) else (
set "Line=!Line:*:=!"
if "!Line:~0,1!!Line:~-1!" == "[]" (
echo !EntryName!=!EntryValue!
if defined EmptyLines for /L %%J in (1,1,!EmptyLines!) do echo(
echo !Line!
endlocal
set "EntryUpdate=3"
set "CopyLines=1"
) else (
if defined EmptyLines for /L %%L in (1,1,!EmptyLines!) do echo(
for /F delims^=^=^ eol^= %%J in ("!Line!") do (
if /I not "%%~J" == "!EntryName!" (
echo !Line!
endlocal
) else (
echo !EntryName!=!EntryValue!
endlocal
set "EntryUpdate=2"
set "CopyLines=1"
)
)
set "EmptyLines="
)
)
)
))>"%TempFile%"
if not defined EntryUpdate (
>>"%TempFile%" echo %SectionName%
>>"%TempFile%" echo %EntryName%=%EntryValue%
set EntryUpdate=4
)
if %EntryUpdate% == 1 (
>>"%TempFile%" echo %EntryName%=%EntryValue%
set "EntryUpdate=3"
)
move /Y "%TempFile%" %1 2>nul
if errorlevel 1 (
echo Failed to update: %1>>"%LogFile%"
del "%TempFile%"
goto :EOF
)
if %EntryUpdate% == 2 (
echo Value updated in: %1>>"%LogFile%"
goto :EOF
)
if %EntryUpdate% == 3 (
echo Entry added to: %1>>"%LogFile%"
goto :EOF
)
if %EntryUpdate% == 4 (
echo Section+entry to: %1>>"%LogFile%"
goto :EOF
)
:ValueExists
echo Value existed in: %1>>"%LogFile%"
del "%TempFile%"
goto :EOF
:EndBatch
endlocal
File related variables defined at top
The log file is created in directory of the batch file with batch file name, but with file extension .log.
The temporary file is created on local machine in directory for temporary files with batch file name, but with file extension .tmp.
The list file containing the computer names or IP addresses must be PCList.txt in directory of the batch file.
Explanation of main code
For each line in the list file not starting with ; the first FOR loop calls a subroutine with the full file name of the INI file to update with appropriate UNC path. A semicolon at beginning of a line can be used to comment out a computer name or IP address.
Requirements for the INI file update routine
The subroutine is written to fulfill following requirements:
The subroutine should not modify the INI file if it contains already the entry to update with the correct value in correct section. I don't like it setting archive attribute and modifying the last modification date of a file if the file contents is not really modified at all.
It should replace the value of the entry in the correct section on being different to the value defined at top of the batch file.
It should add the entry with the wanted value to the section if the section is already existing, but does not yet contain the entry. The entry should be added after last non-empty line of the section.
It should add the section and the entry with the wanted value at end of the file if the file does not contain the section at all.
The subroutine is written to keep all empty lines in file, except empty lines at end of the file if just the entry or the section and the entry must be appended at end of the file. It does not add empty lines. It could be enhanced to additionally reformat an INI file with making sure that there is always exactly one empty line above a section except at top of the file.
Sample set of files
There were six files used in current directory for testing with using as first FOR loop the following command line instead of the command line in posted batch file code:
for %%I in (*.ini) do call :UpateIniFile "%%I"
File1.ini with having the section and the entry, but with wrong value:
[SAMPLE SETTINGS]
SERVER=MYPC
Reboot=0
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
File2.ini with having the section and the entry with the wanted value:
[SAMPLE SETTINGS]
SERVER=MYPC
Reboot=1
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
File3.ini with having the section at top, but not containing the entry:
[SAMPLE SETTINGS]
SERVER=MYPC
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
File4.ini with missing the section completely:
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
File5.ini with having the section at end, but not containing the entry:
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
[SAMPLE SETTINGS]
SERVER=MYPC
File6.ini is like File1.ini, but read-only attribute is set for this file.
Results for sample set of files
The batch file writes to the log file for this sample set:
Value updated in: "File1.ini"
Value existed in: "File2.ini"
Entry added to: "File3.ini"
Section+entry to: "File4.ini"
Entry added to: "File5.ini"
Failed to update: "File6.ini"
File2.ini and File6.ini are not updated at all.
The other four files have the following lines after batch file execution:
File1.ini:
[SAMPLE SETTINGS]
SERVER=MYPC
Reboot=1
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
File3.ini:
[SAMPLE SETTINGS]
SERVER=MYPC
Reboot=1
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
File4.ini:
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
[SAMPLE SETTINGS]
Reboot=1
File5.ini:
[SECTION2]
SETTINGX=1234
[SECTION3]
SETTINGX=4567
[SAMPLE SETTINGS]
SERVER=MYPC
Reboot=1
So the batch file makes a good job for the sample set of files.
Explanation of INI file update routine
There is first checked if the file to update is found at all and an appropriate information is appended to the log file if the file cannot be found.
The subroutine undefines next three environment variables used in the code below.
The FOR loop used in subroutine UpateIniFile is explained in full detail by my answer on
How to read and print contents of text file line by line?
Every line in the INI file output by FINDSTR with line number and colon at beginning is assigned first to environment variable Line with delayed expansion not enabled to prevent line corruption on containing exclamation marks.
Next delayed expansion is enabled which results in creating also a copy of the existing environment variables. Please read lower half of this answer for details about the commands SETLOCAL and ENDLOCAL. It is really important to understand what these two commands do to understand the rest of the code.
The first IF condition is true if the entry of which value should be updated is already in the temporary file with the wanted value and so all remaining lines in the file can be copied to temporary file without any further processing. In this case the line read from file is output with removing the line number and the colon added by FINDSTR to the line.
The second IF condition is true if the section defined at top of the batch file was not found up to current line. In this case the line read from file is also output with line number and colon, but an additional case-insensitive string comparison is done to find out if this line contains the section of interest. If the section of interest is found, the environment variable EntryUpdate is defined with value 1 in the environment defined on entering the subroutine.
Otherwise the current line is below the section of interest.
If this line without line number and colon is case-insensitive equal the entry to update with wanted value, the processing of the lines can be stopped as the file contains the entry already with the wanted value. Command GOTO is used to exit the FOR loop and continue batch file processing below the batch label ValueExists where the temporary file is deleted and the information is written into the log file that the value exists already in the current file before leaving the subroutine.
If the line in section of interest without line number and colon is an empty line, the environment variable EmptyLines is incremented by one in previous environment as defined on entering the subroutine. The value 0 is used on EmptyLines not defined all as explained by help of command SET. There is nothing else done on line in section of interest is an empty line.
For a non-empty line in section of interest the environment variable Line is first redefined with removal of line number and colon for easier processing this line further.
The next condition compares case-sensitive the first and the last character of the line extra enclosed in double quotes with the string "[]" to find out if this line is the beginning of a new section. If this condition is true, the section of interest does not contain the entry at all. Therefore the entry with the wanted value is output now and next all empty lines found perhaps before the new section not yet output. Then the line with the new section is output and in environment defined on entering the subroutine the environment variable EntryUpdate is redefined with string value 3 and environment variable CopyLines is defined as all other lines in file can now be just copied to the temporary file.
But if the current line is not a new section, it is a non-empty line in section of interest. It could be the line with the entry of which value is not the wanted value or a different entry. Therefore first all empty lines are output first which are perhaps above the current entry line in section of interest.
Next one more command FOR is used to split up the current line and get assigned to the loop variable J the string left to first equal sign (after zero or more equal signs at beginning of the line which hopefully no INI file contains ever).
If the current line in section of interest is case-insensitive not the entry of which value should be updated, the entry line is simply output. Otherwise the entry line to update is found and so the line is output with the entry name and the wanted value before the environment variable EntryUpdate is redefined with string value 2 and environment variable CopyLines is defined to copy all other lines simply to the temporary file.
Everything output inside the FOR loop processing the lines of the INI file is redirected into the temporary file.
It could be that current INI file does not contain the section of interest at all which can be found out after processing all lines by checking if the environment variable EntryUpdate is still not defined. In this case the section and the entry with the wanted value is appended to the temporary file with ignoring environment variable EmptyLines to ignore all empty lines at bottom of the INI file.
It is also possible that the last section in the INI file is the section of interest, but the entry with the value to update is not found up to the end of the file. So one more IF condition is used to check if it is necessary to append at end of the file with ignoring all empty lines at end of the file the entry line with the wanted value.
Now the temporary file contains the lines which the just processed INI file should contain after finishing batch file execution. So the temporary file is moved to INI file directory with replacing the INI file if it is not read-only or write-protected by file permissions or write-protected by file access permissions because of being currently opened by the application using this INI file.
If the current INI file cannot be replaced with the wanted modification, the temporary file is deleted and this error condition is recorded in the log file. Otherwise the current INI file is successfully updated and that is recorded in the log file with the information how the update was done by the batch file.
Additional information
It should be clear now that the Windows command processor is not designed for file contents modification because it is designed for running commands and executables. There are lots of script interpreters more suitable for this task than cmd.exe.
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 /?
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
set /?
setlocal /?
See also: Where does GOTO :EOF return to?
What I ended up with:
#echo off
setlocal EnableExtensions Disabledelayedexpansion
set TODAY=%Date:~4,2%-%Date:~7,2%-%Date:~10,4%
set Target=SMSStart.ini
set SectionName=[Maintenance]
set EntryName=Reboot
set EntryValue=1
set LogFile=./INI_VAL_CHANGE_%TODAY%_Log.txt
set TempFile=%TEMP%\%~n0.tmp
set ListFile=PCList.txt
if not exist "./%ListFile%" (
echo ERROR: List file %ListFile%" not found.>"%LogFile%"
goto EndBatch
)
XCOPY /Y %~dp0*_log.txt %~dp0%LOGS>nul
ERASE %~dp0*_log.txt /Q
Echo PC list: %ListFile%
Echo Run: %DATE%:%TIME%
Echo PC list: %ListFile%>>%LogFile%
Echo Run: %DATE%:%TIME%>>%LogFile%
Echo Target File: %Target%
Echo Target File: %Target%>>%LogFile%
Echo Search Key: %EntryName%= Update: "%EntryName%=%EntryValue%"
Echo Search Key: %EntryName%= Update: "%EntryName%=%EntryValue%">>%LogFile%
Echo =============================
Echo =============================>>%LogFile%
for /F "usebackq delims=" %%I in ("%ListFile%") do call :UpateIniFile "\\%%I\Storeman\%Target%"
goto EndBatch
:UpateIniFile
set "EmptyLines="
set "EntryUpdate="
set "CopyLines="
(for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" %1 2^>nul') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
if defined CopyLines (
echo(!Line:*:=!
endlocal
) else if not defined EntryUpdate (
echo(!Line:*:=!
if /I "!Line:*:=!" == "!SectionName!" (
endlocal
set "EntryUpdate=1"
)
) else (
if /I "!Line:*:=!" == "!EntryName!=!EntryValue!" (
endlocal
goto ValueExists
)
if "!Line:*:=!" == "" (
endlocal
set /A EmptyLines+=1
) else (
set "Line=!Line:*:=!"
if "!Line:~0,1!!Line:~-1!" == "[]" (
echo !EntryName!=!EntryValue!
if defined EmptyLines for /L %%J in (1,1,!EmptyLines!) do echo(
echo !Line!
endlocal
set "EntryUpdate=3"
set "CopyLines=1"
) else (
if defined EmptyLines for /L %%L in (1,1,!EmptyLines!) do echo(
for /F delims^=^=^ eol^= %%J in ("!Line!") do (
if /I not "%%~J" == "!EntryName!" (
echo !Line!
endlocal
) else (
echo !EntryName!=!EntryValue!
endlocal
set "EntryUpdate=2"
set "CopyLines=1"
)
)
set "EmptyLines="
)
)
)
))>"%TempFile%"
if not defined EntryUpdate (
>>"%TempFile%" echo %SectionName%
>>"%TempFile%" echo %EntryName%=%EntryValue%
set EntryUpdate=4
)
if %EntryUpdate% == 1 (
>>"%TempFile%" echo %EntryName%=%EntryValue%
set "EntryUpdate=3"
)
move /Y "%TempFile%" %1 2>nul
if errorlevel 1 (
echo Failed to update: %1 : !time:~0,8!
echo Failed to update: %1 : !time:~0,8!>>"%LogFile%"
del "%TempFile%"
goto :EOF
)
if %EntryUpdate% == 2 (
echo !EntryName!=!EntryValue! updated in: %1 : !time:~0,8!
echo !EntryName!=!EntryValue! updated in: %1 : !time:~0,8!>>"%LogFile%"
goto :EOF
)
if %EntryUpdate% == 3 (
echo !EntryName!=!EntryValue! added to: %1 : !time:~0,8!
echo !EntryName!=!EntryValue! added to: %1 : !time:~0,8!>>"%LogFile%"
goto :EOF
)
if %EntryUpdate% == 4 (
echo Section+ !EntryName!=!EntryValue! to: %1 : !time:~0,8!
echo Section+ !EntryName!=!EntryValue! to: %1 : !time:~0,8!>>"%LogFile%"
goto :EOF
)
:ValueExists
echo !EntryName!=!EntryValue! existed in: %1 : !time:~0,8!
echo !EntryName!=!EntryValue! existed in: %1 : !time:~0,8!>>"%LogFile%"
del "%TempFile%"
goto :EOF
:EndBatch
endlocal
pause
#Mofi - Trying to shore up the code as per your suggestions:
move /Y "%TempFile%" %1 2>nul
if errorlevel 1 (
echo Failed to update: %1 : !time:~0,8!
echo Failed to update: %1 : !time:~0,8!>>"%LogFile%"
del "%TempFile%"
goto :EOF
Trying to figure out why when the batch is unable to reach a PC on the network and outputs an errorlevel 1, the script returns !time:~0,8! rather than the actual timestamp?
Here is the current version I am working from:
#echo off
setlocal EnableExtensions Disabledelayedexpansion
set "TODAY=%Date:~4,2%-%Date:~7,2%-%Date:~10,4%"
set "Target=SMSStart.ini"
set "TarDIR=Storeman"
set "SectionName=[Maintenance]"
set "EntryName=Reboot"
set "EntryValue=1"
set "LogFile=.\INI_VAL_CHANGE_%TODAY%_Log.txt"
set "TempFile=%TEMP%\%~n0.tmp"
set "ListFile=PCList.txt"
if not exist ".\%ListFile%" (
echo ERROR: List file %ListFile%" not found.>"%LogFile%"
goto EndBatch
)
XCOPY /Y "%~dp0*_log.txt" %~dp0%LOGS>nul
ERASE "%~dp0*_log.txt" /Q
Echo INI File Updater
Echo INI File Updater>>%LogFile%
Echo ==============================
Echo ==============================>>%LogFile%
Echo PC list: %ListFile%
Echo Run: %DATE%:%TIME%
Echo PC list: %ListFile%>>%LogFile%
Echo Run: %DATE%:%TIME%>>%LogFile%
Echo Target File: %Target%
Echo Target File: %Target%>>%LogFile%
Echo Target DIR: \%TarDIR%
Echo Target DIR: \%TarDIR%>>%LogFile%
Echo INI Section : %SectionName%
Echo INI Section : %SectionName%>>%LogFile%
Echo Search Key: %EntryName%= Update: "%EntryName%=%EntryValue%"
Echo Search Key: %EntryName%= Update: "%EntryName%=%EntryValue%">>%LogFile%
Echo ==============================
Echo.
Echo ==============================>>%LogFile%
Echo.>>%LogFile%
for /F "usebackq delims=" %%I in ("%ListFile%") do call :UpateIniFile "\\%%I\%TarDIR%\%Target%"
goto EndBatch
:UpateIniFile
set "EmptyLines="
set "EntryUpdate="
set "CopyLines="
(for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" %1 2^>nul') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
if defined CopyLines (
echo(!Line:*:=!
endlocal
) else if not defined EntryUpdate (
echo(!Line:*:=!
if /I "!Line:*:=!" == "!SectionName!" (
endlocal
set "EntryUpdate=1"
)
) else (
if /I "!Line:*:=!" == "!EntryName!=!EntryValue!" (
endlocal
goto ValueExists
)
if "!Line:*:=!" == "" (
endlocal
set /A EmptyLines+=1
) else (
set "Line=!Line:*:=!"
if "!Line:~0,1!!Line:~-1!" == "[]" (
echo !EntryName!=!EntryValue!
if defined EmptyLines for /L %%J in (1,1,!EmptyLines!) do echo(
echo !Line!
endlocal
set "EntryUpdate=3"
set "CopyLines=1"
) else (
if defined EmptyLines for /L %%L in (1,1,!EmptyLines!) do echo(
for /F delims^=^=^ eol^= %%J in ("!Line!") do (
if /I not "%%~J" == "!EntryName!" (
echo !Line!
endlocal
) else (
echo !EntryName!=!EntryValue!
endlocal
set "EntryUpdate=2"
set "CopyLines=1"
)
)
set "EmptyLines="
)
)
)
))>"%TempFile%"
if not defined EntryUpdate (
>>"%TempFile%" echo %SectionName%
>>"%TempFile%" echo %EntryName%=%EntryValue%
set EntryUpdate=4
)
if %EntryUpdate% == 1 (
>>"%TempFile%" echo %EntryName%=%EntryValue%
set "EntryUpdate=3"
)
move /Y "%TempFile%" %1 2>nul
if errorlevel 1 (
echo Failed to update: %1 : !time:~0,8!
echo Failed to update: %1 : !time:~0,8!>>"%LogFile%"
del "%TempFile%"
goto :EOF
)
if %EntryUpdate% == 2 (
echo !EntryName!=!EntryValue! updated in: %1 : !time:~0,8!
echo !EntryName!=!EntryValue! updated in: %1 : !time:~0,8!>>"%LogFile%"
goto :EOF
)
if %EntryUpdate% == 3 (
echo !EntryName!=!EntryValue! added to: %1 : !time:~0,8!
echo !EntryName!=!EntryValue! added to: %1 : !time:~0,8!>>"%LogFile%"
goto :EOF
)
if %EntryUpdate% == 4 (
echo Section+ !EntryName!=!EntryValue! to: %1 : !time:~0,8!
echo Section+ !EntryName!=!EntryValue! to: %1 : !time:~0,8!>>"%LogFile%"
goto :EOF
)
:ValueExists
echo !EntryName!=!EntryValue! existed in: %1 : !time:~0,8!
echo !EntryName!=!EntryValue! existed in: %1 : !time:~0,8!>>"%LogFile%"
del "%TempFile%"
goto :EOF
:EndBatch
Echo.
Echo.>>%LogFile%
Echo ---COMPLETE---
Echo ---COMPLETE--->>"%LogFile%"
Echo.
endlocal
pause

Windows Batch Script for SVN & reviewboard

I'm a newbie to batch scripting. i have written a below script but it was not running. Please let me know whether i'm missing any syntax or something.
Script Procedure :- The variable %MESSAGEFILE% will contain two lines of strings Example :- PID-PROJECTID DEV SFRNUM:0123
Review:123
If missing anyone line should throw error in block :Commitmsg Otherwise it should proceed.
#echo off
setlocal enabledelayedexpansion
set BASEDIR=%CD%
set URL=https://*******:443/reviewboard/
set YES=YES
set MESSAGEFILE=%2%
:: Checking If the API File Exists or Not. If Not Prompt Users to Create
IF NOT EXIST C:\api (
echo Please Create a File api under C:\ and provide ur API details in it 1>&2
exit 1
)
for /f "tokens=*" %%i in ('type "C:\api"') do (
set API=%%i
)
:: Comment Message Validations
type %MESSAGEFILE% > tmpFile
set "file=tmpFile"
call :Commitmsg "%file%"
type %BASEDIR%\tmpFile |findstr /IB "PID" > tmpFile1
set "file=tmpFile1"
call :Commitmsg "%file%"
type %BASEDIR%\tmpFile |findstr /IB "Review" > tmpFile2
set "file=tmpFile2"
call :Commitmsg "%file%"
:: Checking If SVN Command Client is Installed. If yes Store Some svn info into Variables
svn info > svninfo
IF ERRORLEVEL 1 (
echo Seems like SVN Command-line Client Not Installed. Please Install it. Contact Vercon For Support 1>&2
goto :delFiles
)
for /f "tokens=4 delims=//" %%i in ('findstr /ilc:"Repository Root" "svninfo"') do (
set REP=%%i
)
for /f "tokens=3 delims=^/" %%j in ('findstr /ilc:"Relative URL" "svninfo"') do (
set TARGET_GROUPS=%%j
)
FOR /F "tokens=*" %%F IN (tmpFile1) DO (
set msg=%%F
)
FOR /F "tokens=2 delims=:" %%F IN (tmpFile2) DO (
set rev=%%F
)
FOR /F "tokens=* delims= " %%a IN ("%rev%") DO (
SET rev=%%a
)
:: Creating .reviewboardrc file
echo REVIEWBOARD_URL = "%URL%" >> .reviewboardrc
echo REPOSITORY = "%REP%" >> .reviewboardrc
echo DISABLE_SSL_VERIFICATION = "%YES%" > .reviewboardrc
echo API_TOKEN = "%API%" >> .reviewboardrc
echo TARGET_GROUPS = "%TARGET_GROUPS%" >> .reviewboardrc
echo PUBLISH = "%YES%" >> .reviewboardrc
echo OPEN_BROWSER = "%YES%" >> .reviewboardrc
:: Posting Reviews Based On Comment Message in SVN
if /I "%rev:new=%" neq "%rev%" (
rbt post --summary %msg% --description %msg%
goto :delFiles
) else (
rbt post -r %rev% --summary %msg% --description %msg%
goto :delFiles
)
:: Error Message in Case Of Wrong Commit Message in SVN
:Commitmsg
if %~z1 == 0 (
echo Please Provide the Commit Message in the First Line, Followed by review. 1>&2
echo The First Line will be Taken as a Review Summary. 1>&2
echo Follow the Below Example 1>&2
echo ************************************************************ 1>&2
echo PID-PROJECTID DEV SFRNUM:01234 1>&2
echo Review:New / Review:01 1>&2
echo To Create a New Review -- Review:New 1>&2
echo To Update a Existing Review -- Review:01 1>&2
echo ************************************************************ 1>&2
echo Contact Vercon Team For Support 1>&2
goto :delFiles
)
:delFiles
IF EXIST tmpFile del tmpFile
IF EXIST tmpFile1 del tmpFile1
IF EXIST tmpFile2 del tmpFile2
IF EXIST .reviewboardrc del .reviewboardrc
IF EXIST svninfo del svninfo
exit 1
A small Correction Worked !. Please dont waste your valuable time on this as i found the solution.
Thanks !

Inputting space in prompts crash batch file

I am trying to do a command line replica compeletely out of boredom and I have an issue. Here is my code:
#echo off
set /a secret=1
color B
title Subnet Access v1.0
echo ____________________________________________________________
echo / I
echo I Subnet Access v1.0 I
echo I____________________________________________________________/
echo.
echo.
timeout 3 > NUL
echo sys rev init
timeout 1 >NUL
echo loading keyframes
echo please wait
timeout 5 >NUL
echo.
echo.
echo Checking for alerts
timeout 6 >NUL
echo alert 0-21-77
timeout 1 >NUL
echo.
set /p pid=enter pid: || set pid=empty
IF "%pid%"=="1123321231" (
echo.
set /a "secret+=1"
cls
echo Secrets %secret%/10 found.
timeout 3 >NUL
cls
echo.
echo pid confirmed
timeout 1 >NUL
echo checking with server...
timeout 5 >NUL
cls
color C
echo COULD NOT IDENTIFY
timeout 1 >NUL
cls
echo.
timeout 1 >NUL
cls
echo COULD NOT IDENTIFY
timeout 1 >NUL
cls
echo.
timeout 1 >NUL
cls
echo COULD NOT IDENTIFY
timeout 1 >NUL
cls
echo.
timeout 1 >NUL
goto :unidentify
)
IF NOT "%pid%"=="1123321231" GOTO :unidentify
:unidentify
cls
echo.
echo unauthorized access
timeout 3 >NUL
echo level drop
timeout 1 >NUL
echo dropping...
timeout 3 >NUL
echo level now 0
timeout 4 >NUL
echo sys exit
timeout 1 >NUL
cls
cls
set su=0
color 7
title sys/rev/console-override
echo Subnet Console v0.1
echo Made by Murtaugh
echo.
:sub01 ::PROBLEM STARTS HERE
IF %su%==0 (
set /p commandMur=sys/dev/: #^> || set commandMur=emptycom
)
IF %su%==1 (
color B
set /p commandMur=sys/dev/: $^> || set commandMur=emptycom
)
IF %commandMur%==help (
::help segment
echo.
echo Help v0.1 Alpha by Murtaugh
echo.
echo Commands are listed below:
echo dir - Lists your directory's contents.
echo help - Shows this page.
echo connect - Connects you to an IP address.
echo.
goto :sub01
)
IF "%commandMur%"=="exit" (
goto :eof
)
IF "%commandMur%"=="cls" (
cls
goto :sub01
)
IF "%commandMur%"=="su" IF "%su%"=="0" (
cls
echo.
set /a "secret+=1"
echo Secrets %secret%/10 found.
set su=1
goto :sub01
)
IF "%commandMur%"=="su" IF "%su%"=="1" (
goto :sub01
)
IF "%commandMur%"=="emptycom" (
goto :sub01
)
IF NOT "%commandMur%"=="exit" IF NOT "%commandMur%"=="help" IF NOT "%commandMur%"=="cls" IF NOT "%commandMur%"=="su" (
echo "%commandMur%": Bad command or file name
echo.
goto :sub01
) ::PROBLEM ENDS HERE
But when I input something with spaces it says test==exit was unexpected at this time. and just close. Is there anyway I can fix this? Thanks.
EDIT: Tried "%prompt%"=="test" thing, doesn't work.
test==exit was unexpected ... is a typical syntax error with if (set doesn't give this type of error).
Most likely you have a if %command%==exit ...-command the next line. To avoid the syntax error, write if "%command%"=="exit" ...
im not really a great programmer, but try adding "QUOTATION TAGS" when you type text with spaces, beacuse batch sometimes get confused about those spaces

Is there any way to programmatically add a startup script to the local group policy?

I need to write a script that can add itself to the startup scripts in the local group policy so that it can run even when no users are logged in. This can be done using gpedit.msc and going into Computer Configuration > Windows Settings > Scripts > Startup. However, I haven't found a way to do this programmatically.
I've looked into simply editing the registry. I found the relevant location to be HKLM\Software\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\Startup, but simply adding my own entry does not have any effect. The computer is not part of a domain.
Does anyone know how to do this? Is there a WMI approach?
I think you have to modify %windir%\system32\GroupPolicy\gpt.ini, appending [{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}] to the gPCMachineExtensionNames line and incrementing the Version value by one. (source).
Try adding and removing a script via group policy editor and you can watch how gpt.ini changes. When you add a script, you can also use the structure created in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\Startup\0 as a template.
For anyone coming across this thread whose machine is a member of a domain, I've noticed that domain-defined group policies appear in the registry after local policies. So if you've already got a domain policy at ...\Scripts\Startup\0, you should copy it to ...\Scripts\Startup\1 before creating your local machine policy.
In any case, expirement with the GUI and see how stuff changes before attempting programmatically.
You'll also need to run gpupdate to refresh group policies.
I am working on a script for this and my testing shows you do not have to edit the registry at all. Follow these steps and it will work
Find the last script number in scripts.ini (There are two lines for each script "0CmdLine=" and "0Parameters=".
Add two lines for each of your scripts to be added (e.g. "1CmdLine=myscript.vbs" and "1Parameters="
Increment the "version=" number in gpt.ini
Run Gpupdate to apply it
Important Note for scripting a solution: gpt.ini uses UTF-8 encoding, scripts.ini uses Unicode. Cheers M$!
Hope this helps people.
Shaun
Just configure it manually on one machine and run gpupdate /force. Then copy %systemroot%\System32\GroupPolicy from your source machine to %systemroot%\System32\GroupPolicy on the rest of your machines.
even though it's an older post, i think people might still be looking for the same scenario (as was i).
please find below a batch of mine for extending the scripts.ini.
you only need 2 or 3 parameters, example at the end of the script.
also, keep in mind to edit the gpt.ini if required!
more information on the gpt.ini here
easiest way to determine the GUIDs is to edit in gpedit.msc and watch the changes.
please be careful with the script and test it before use in productive environment!
#echo off
setlocal enabledelayedexpansion
REM get parameter for scripts.ini changes
if not "%~1"=="" (
set type=%1
) else (
goto enderror
)
if not "%~2"=="" (
set cmd=%2
) else (
goto enderror
)
if not "%~3"=="" (
set params=%3
) else (
set params=
)
if not exist scripts.ini echo. 2>scripts.ini
if exist scripts.ini (
set ctr=0
for /f %%a in (scripts.ini) do (
echo %%a | findstr /C:"[Logon]" 1>nul
if not errorlevel 1 (
set /a ctr+=1
)
)
if !ctr!==0 (
echo [Logon]>>scripts.ini
)
set ctr=0
for /f %%a in (scripts.ini) do (
echo %%a | findstr /C:"[Logoff]" 1>nul
if not errorlevel 1 (
set /a ctr+=1
)
)
if !ctr!==0 (
echo [Logoff]>>scripts.ini
)
)
REM remove scripts-new.ini if exists
if exist scripts-new.ini (
del /F /Q scripts-new.ini
)
REM ctr = number at front for each cmd-param pair - subctr = counter for lines --> pairs - diff = change from Logon to Logoff or vice versa
set ctr=0
set subctr=0
set diff=0
set used=0
for /f %%a in (scripts.ini) do (
set line=%%a
echo !line! | findstr /C:"[Logoff]" 1>nul
if not errorlevel 1 (
if !diff!==1 goto endlogon
)
echo !line! | findstr "CmdLine=!cmd!" 1>nul
if not errorlevel 1 (
set /a used+=1
)
if !diff!==1 (
echo !ctr!!line:~1!>>scripts-new.ini
set /a subctr+=1
if !subctr!==2 (
set /a ctr+=1
set subctr=0
)
)
echo !line! | findstr /C:"[Logon]" 1>nul
if not errorlevel 1 (
set diff=1
echo !line!>>scripts-new.ini
)
)
:endlogon
if /I !type!==logon if !used!==0 (
echo !ctr!CmdLine=!cmd!>>scripts-new.ini
echo !ctr!Parameters=!params!>>scripts-new.ini
)
set ctr=0
set diff=0
set used=0
for /f %%a in (scripts.ini) do (
set line=%%a
echo !line! | findstr /C:"[Logon]" 1>nul
if not errorlevel 1 (
if !diff!==1 goto endlogoff
)
echo !line! | findstr "CmdLine=!cmd!" 1>nul
if not errorlevel 1 (
set /a used+=1
)
if !diff!==1 (
echo !ctr!!line:~1!>>scripts-new.ini
set /a subctr+=1
if !subctr!==2 (
set /a ctr+=1
set subctr=0
)
)
echo !line! | findstr /C:"[Logoff]" 1>nul
if not errorlevel 1 (
set diff=1
echo !line!>>scripts-new.ini
)
)
:endlogoff
if /I !type!==logoff if !used!==0 (
echo !ctr!CmdLine=!cmd!>>scripts-new.ini
echo !ctr!Parameters=!params!>>scripts-new.ini
)
goto end
:enderror
echo Usage: scripts-extender.bat [LOGON ^| LOGOFF] [Script Name] "[optional Parameters for Script - WITH QUOTES!]"
echo Example: scripts-externder.bat logon netlogon.bat "param1 param2"
:end
move /Y scripts.ini scripts-old.ini
move /Y scripts-new.ini scripts.ini

Resources