Grepping one of "reg query" result values - windows

In order to get the current Office installation path,
I set up this line
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WINWORD.EXE"
and the result is:
(Default) REG_SZ C:\PROGRA~1\MICROS~1\Office16\WINWORD.EXE
Path REG_SZ C:\Program Files\Microsoft Office\Office16\
useURL REG_SZ 1
SaveURL REG_SZ 1
How to grep out the "C:\Program Files\Microsoft Office\Office16\" in a variable?
Thanks.

By using the command line
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\winword.exe" /v Path
just the string value of Path is output which means on Windows XP:
 
! REG.EXE VERSION 3.0
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\winword.exe
Path REG_SZ C:\Program Files\Microsoft Office\Office16\
So this output starts with an empty line, a header of reg.exe version 3.0, one more empty line, the queried registry key and the queried registry value Path if found at all in Windows registry under specified key. There is a tab character between Path and REG_SZ and one more tab character between REG_SZ and the path string. The line with Path starts with four spaces.
On Windows Vista and later Windows versions the output is:
 
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\winword.exe
Path REG_SZ C:\Program Files\Microsoft Office\Office16\
This output starts with an empty line like on Windows XP. But output is next already the queried registry key without any additional header. Last the line with queried registry value Path is output if found at all in Windows registry under specified key. The last line starts also with four spaces like on Windows XP. But there are four spaces between Path and REG_SZ and four spaces between REG_SZ and the path string instead of horizontal tabs.
This means for getting the path string using command FOR with option /F:
The first two lines of output of command REG can be always skipped.
It is necessary to check if third line contains already value Path or one more non empty line needs to be processed to have a batch file working also on Windows XP.
The last line has space or tab separated the strings Path, REG_SZ and the path string which could contain also 1 or more spaces or any other character allowed in a folder name.
The batch file code for this task:
#echo off
for /F "skip=2 tokens=1,2*" %%A in ('%SystemRoot%\System32\reg.exe query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\winword.exe" 2^>nul') do (
if /I "%%A" == "Path" if not "%%~C" == "" set "OfficePath=%%~C" & goto FoundPath
)
echo Could not determine MS Office path. MS Office is most likely not installed.
echo/
pause
goto :EOF
:FoundPath
rem Remove backslash at end of path if there is one at all.
if "%OfficePath:~-1%" == "\" set "OfficePath=%OfficePath:~0,-1%"
echo MS Office is installed in: "%OfficePath%"
rem Other command using environment variable OfficePath.
The command FOR executes in a background process started with cmd.exe /C the command line (with %SystemRoot% already expanded):
%SystemRoot%\System32\reg.exe query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\winword.exe" 2>nul
The output of this command process (= reg.exe) written to handle STDOUT is captured by FOR.
REG outputs to handle STDERR an error message if either the specified registry key or the specified registry value does not exist at all in Windows registry. This error output is redirected to device NUL to suppress it. Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded reg command line with using a separate command process started in background.
The command FOR could have nothing to process in case of registry key or registry value not found by REG resulting in execution of the command lines below the FOR loop informing the batch file user about this use case.
Otherwise command FOR skips because of skip=2 the first two captured lines which means on Windows Vista and later the first line processed by FOR is already the line containing Path. On Windows XP the third line being an empty line is ignored by FOR and the next line with queried registry key is processed next.
The line is split up because of tokens=1,2* and the default delimiters space/tab into 3 substrings.
On Windows Vista and later Windows:
Path is assigned to specified loop variable A.
REG_SZ is assigned to next loop variable B according to ASCII table.
C:\Program Files\Microsoft Office\Office16\ is assigned to loop variable C.This third string is not further split up on spaces/tabs because of *.
On Windows XP the first line tokenized by FOR results in:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App being assigned to specified loop variable A and
Paths\winword.exe being assigned to next loop variable B.
Nothing is assigned to loop variable C because there is no more string on processed line.
A case-insensitive string comparison of value of loop variable A is made with fixed string Path to verify if FOR processed already the right line with Path value. On Windows Vista and later Windows versions this is already true on first line tokenized by FOR. On Windows XP this condition is first false and FOR processes therefore the next line now assigned the same strings to the loop variables A, B and C as on Windows Vista and later Windows versions.
On a true condition the path string assigned to loop variable C and not being an empty string is assigned to environment variable OfficePath with removing enclosing double quotes if the path string is enclosed at all in ". And next a jump is made to label FoundPath exiting the loop and continue batch file execution in code block on having the MS Office path.
In this code block first a backslash at end of path is removed if there is one at all to have assigned to environment variable OfficePath always the path string without a backslash at end independent on path string in registry not having or having a backslash at end using string substitution.
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.
echo /?
for /?
goto /?
if /?
pause /?
reg /?
reg query /?
rem /?
set /?

From cmd.exe if you run reg query /? there is a specific switch that stands out.
/v Queries for a specific registry key values.
If omitted, all values for the key are queried.
When looking at your complete output, you are very specifically requiring the registry key value Path
So by Simply running:
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WINWORD.EXE" /v Path
we get less noise to deal with.
With that logic, here is the batch which simply uses the : of the path string extracted as the delimiter and then joining %%a being C Drive, with %%b being rest of the path after : and we simply just join them again with the colon.
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1,2 delims=:" %%a in ('reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WINWORD.EXE" /v Path') do (
set result=%%a
set result=!result:~-1!
set output=!result!:%%b
)
echo !output!

Just use the (javascript) regex .:(?!.*:).*
What this captures is:
.: - Drive letter
(?!.*:) - Not followed by other colons (illegal in Windows paths)
.* - Followed by the path

Related

Trying to rename all files ending with "VA.pdf" to "PA.pdf" using batch code

Hello I am trying to rename all files ending with "VA.pdf" to "PA.pdf" using batch code
I tired this code but it is not working
REN *VA.pdf *PA.pdf
Appreciate any help
There can be used for this file renaming task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
if exist "*!*VA.pdf" goto ExtendedVersion
setlocal EnableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir *VA.pdf /A-D-L /B 2^>nul') do (
set "FileNamePDF=%%~nI"
set "FileNameNew=!FileNamePDF:~0,-2!PA%%~xI"
if not exist "!FileNameNew!" ren "!FileNamePDF!%%~xI" "!FileNameNew!"
)
endlocal
goto EndBatch
:ExtendedVersion
echo INFO: Extended version required because of a PDF file with exclamation marks.
for /F "eol=| delims=" %%I in ('dir *VA.pdf /A-D-L /B 2^>nul') do (
set "FileNamePDF=%%~nI"
setlocal EnableDelayedExpansion
set "FileNameNew=!FileNamePDF:~0,-2!PA%%~xI"
if not exist "!FileNameNew!" ren "!FileNamePDF!%%~xI" "!FileNameNew!"
endlocal
)
:EndBatch
endlocal
There is defined first the required execution environment with the first two command lines.
The IF condition in the third command line quickly checks if there is any PDF file with case-insensitive VA in the file name before the file extension .pdf containing one or more exclamation marks in the file name. The extended version of the processing loop is required if this condition is true.
The standard version enables first required delayed expansion. Then a FOR loop is used which runs in background with Windows installed into C:\Windows:
C:\Windows\System32\cmd.exe /c dir *VA.pdf /A-D-L /B 2>nul
The internal command DIR of cmd.exe searches
in the current directory as defined by the process starting cmd.exe for processing the batch file
for just file names because of option /A-D-L (attribute not directory and not link)
matching case-insensitive the wildcard pattern *VA.pdf in long or short 8.3 name
and outputs in bare format because of option /B just the file names with file extension, but without file path.
An error message output to handle STDERR (standard error) on DIR does not find any file system entry matching the criteria is suppressed by redirecting this error message to the device NUL.
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
FOR respectively cmd.exe processing the batch file captures all output written to standard output stream of in background started cmd.exe and processes it line by line after started cmd.exe closed itself after finishing executing the command DIR.
FOR with option /F is used here to get a list of file names of *VA.pdf files loaded into memory of cmd.exe before really doing the file renames as otherwise it could happen especially on FAT drives (FAT32, exFAT) that some PDF files are skipped or processed more than once (on rename not possible).
FOR on using option /F ignores always empty lines which is no problem here as DIR with the used options does not output empty lines.
FOR would next split up the lines into substrings using horizontal tab and normal space as string delimiters, would look next if first tab/space separated string begins with a semicolon in which case it would also ignore the entire line for further processing, and would otherwise assign just the first tab/space separated string to the specified loop variable I before running the commands in body of FOR.
The default line splitting behavior is not wanted as PDF file names can contain one or more spaces. The usage of the option delims= defines an empty list of delimiters which turns off the line splitting behavior.
It is very unusual but nevertheless possible that a PDF file name begins with ; (semicolon). Such a file name should not be ignored by FOR. The option eol=| defines a vertical bar as end of line character which no file name can contain ever. Microsoft lists the characters not allowed in a file name on Windows file systems in the documentation about Naming Files, Paths, and Namespaces.
The current file name without file extension .pdf is assigned first to the environment variable FileNamePDF.
Next a string substitution is used to get from the string value of the environment variable FileNamePDF the file name without the last two characters VA concatenated with the string PA and the file extension .pdf assigned to the environment variable FileNameNew.
If there is not already a PDF file ending with PA in the file name before the file extension, there is next executed the command REN to rename the *VA.pdf file to *PA.pdf.
The command ENDLOCAL after the loop restores the previous environment before enabling delayed expansion and the command GOTO instructs the Windows Command Processor to continue processing the batch file with the command line below the label EndBatch which contains one more ENDLOCAL to restore the environment on starting the batch file processing.
The extended version is nearly the same as the standard version. The difference is that delayed variable expansion is not enabled on assigning the file name of the current VA.pdf file without the file extension to the environment variable FileNamePDF. That avoids interpreting the exclamation mark(s) in the file name as beginning/end of a delayed expanded variable reference resulting in a manipulation of the file name string before assigning it to the environment variable as it would happen with delayed expansion already enabled.
The extended version enables next delayed variable expansion inside the loop, does the same as the standard version and restores finally the previous environment before processing the next *VA.pdf file.
The extended version is slower because of the environment variables list copy and the other operations made in background by every execution of SETLOCAL as explained in full details in this answer. The command ENDLOCAL in the loop is required to avoid a stack overflow on processing lots of PDF files.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
echo /?
endlocal /?
for /?
goto /?
if /?
ren /?
set /?
setlocal /?

How to check if WMIC outputs an empty string or the requested original product key of Windows?

I try to use a wmic command to check for the Windows product key. I put a check to see if it is returning the Windows product key or an empty line. But the conditions IF "%%Z" == "" as well as IF [%%Z] EQU [] result always in execution of Echo Lose, i.e. key is not an empty string.
The following example is a simpler version to show the first part.
#ECHO OFF
set cmd=wmic path softwarelicensingservice get OA3xOriginalProductKey
for /f "tokens=1 skip=1" %%Z in ('%cmd% ^| findstr /r /v "^$"') do (set RESULT=%%Z)
IF "%%Z" == "" (Echo Key %RESULT%) Else (Echo Lose)
PAUSE
The string value assigned to a loop variable like Z cannot be referenced outside of the loop. The condition IF "%%Z" == "" compares always the fixed string "%Z" with the fixed string "" which are of course never equal. The condition IF [%%Z] EQU [] results first in the attempt to convert the fixed string [%Z] into a 32-bit signed integer value which fails already on first character [ and for that reason there is done next a string comparison of [%Z] with [] which are never equal too.
Some facts to know before using the code below:
The SoftwareLicensingService class is available only on Windows Vista or newer Windows client versions and on Windows Server 2008 and newer Windows server versions. This class has no property OA3xOriginalProductKey on Windows Vista and Windows Server 2008.
The SoftwareLicensingService class of Windows 7 and Windows Server 2008 R2 does not have the property OA3xOriginalProductKey too.
There is not written much about OA3xOriginalProductKey in the Microsoft documentations. There are the Microsoft documentation pages Windows 10, version 1703 basic level Windows diagnostic events and fields and An OSD task sequence doesn't continue after Windows Setup or an in-place upgrade finishes and Deploy Windows 10 Enterprise licenses with a little bit of information about OA3xOriginalProductKey. It looks like this property was introduced with OEM Activation 3.0 system used for Windows 8, Windows 8.1 and Windows 10 client versions.
There could be used the following batch code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "RESULT="
for /F "delims=" %%I in ('%SystemRoot%\System32\wbem\wmic.exe PATH SoftwareLicensingService GET OA3xOriginalProductKey /VALUE 2^>nul') do for /F "tokens=1* delims==" %%J in ("%%I") do set "RESULT=%%K"
if not defined RESULT echo Lose& goto EndBatch
echo Key %RESULT%
rem Other commands making use of environment variable RESULT.
:EndBatch
endlocal
pause
The usage of FINDSTR to filter out the empty lines is of no real help in case of no value output by WMIC for property OA3xOriginalProductKey because of the Unicode output of WMIC encoded with UTF-16 Little Endian with byte order mark (BOM) is processed wrong by the cmd.exe instance started in background with option /C and the specified command line as additional arguments on redirecting the output to FINDSTR with conversion to a single byte per character encoding.
The environment variable RESULT is defined in this case with a single carriage return as string assigned to the environment variable.
The workaround for this quirks of cmd.exe on processing the Unicode output of WMIC is using the option /VALUE to get output the name of property OA3xOriginalProductKey and its value on one line with an equal sign between and two empty lines above and also below the data line.
All five captured lines are processed by FOR which usually ignores empty lines completely. But there is no empty line to process by FOR because of the bug of cmd.exe interpreting the UTF-16 encoded carriage return + line-feed (0D 00 0A 00) as carriage return + carriage return + line-feed (0D 0D 0A) resulting in the four empty lines are interpreted as line with a single carriage return and the line with OA3xOriginalProductKey= at beginning as line having also an extra carriage return at the end.
For that reason each entire line with carriage return at end is assigned first to loop variable I.
One more FOR loop is used to process the string assigned to the loop variable I which results in removing the erroneous carriage return from the string value before processing it.
So for the four empty lines there is no string to process by the second FOR and so the four empty lines are indeed ignored.
The second FOR loop splits up the only line with text data into two substrings by using the equal sign as string delimiter. The first substring OA3xOriginalProductKey is assigned to loop variable J and the second substring after the equal sign is the key which is assigned to next but one loop K if there is a key at all as otherwise K is not defined and %%K on command SET executed next is replaced by an empty string.
The batch file defines with the first two lines the required execution environment completely and makes sure that the environment variable RESULT is by chance not already defined outside of the batch file with the third command line.
The IF condition after the long command line with the two FOR and the SET commands checks first if the environment variable RESULT is defined now with a real key (and not with just carriage return) to determine which ECHO command to execute next.
The long command line could be also:
for /F "delims=" %%I in ('%SystemRoot%\System32\wbem\wmic.exe PATH SoftwareLicensingService GET KeyManagementServiceMachine /VALUE 2^>nul') do for /F "tokens=2 delims==" %%J in ("%%I") do set "RESULT=%%J"
In this case just the string after the OA3xOriginalProductKey= is assigned to specified loop variable J if there is a key output by WMIC at all. Otherwise there is nothing to assign to J by second FOR and for that reason the command SET is never executed at all resulting in RESULT still not existing in list of environment variables.
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.
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
wmic /?
wmic path /?
wmic path softwarelicensingservice /?
wmic path softwarelicensingservice get /?
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with using a separate command process started in background.

How to get product name of Windows from Windows registry?

I need to get a value in a registry key with a Windows command.
For example:
reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v ProductName | findstr "REG_")
It outputs:
ProductName REG_SZ Windows 7 Home Premium
I need just the string Windows 7 Home Premium.
The command FOR with option /F can be used to assign the output of a command or executable to an environment variable.
For usage in a batch file:
for /F "skip=2 tokens=1,2*" %%I in ('%SystemRoot%\System32\reg.exe query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v ProductName 2^>nul') do if /I "%%I" == "ProductName" set "WindowsProduct=%%K"
For usage in a command prompt window:
for /F "skip=2 tokens=1,2*" %I in ('%SystemRoot%\System32\reg.exe query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v ProductName 2^>nul') do if /I "%I" == "ProductName" set "WindowsProduct=%K"
FOR starts one more command process in background with %ComSpec% /c and the command line in the parentheses appended as additional arguments. So started is with Windows installed to C:\Windows:
C:\Windows\System32\cmd.exe /c C:\Windows\System32\reg.exe query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v ProductName 2>nul
The output of executable reg.exe is captured by FOR and processed line by line after started cmd.exe closed itself after reg.exe terminated itself.
Read the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded reg command line with using a separate command process started in background.
The output by reg on Windows Vista and later Windows versions is for example:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
ProductName REG_SZ Windows 7 Home Premium
So there is an empty line output first, next the line with the registry key, then the line with the value of interest with spaces around ProductName, REG_SZ and Windows 7 Home Premium, and last one more empty line.
But the output is different on Windows XP:
! REG.EXE VERSION 3.0
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
ProductName REG_SZ Microsoft Windows XP
There is an additional header with two more lines output by reg.exe on Windows XP. There is a horizontal tab character between ProductName and REG_SZ and one more tab between REG_SZ and Microsoft Windows XP instead of spaces in comparison to output of reg.exe on Windows Vista and later Windows versions.
Those differences are taken into account on processing the captured output with FOR.
The first two lines are skipped because of using option skip=2 which means on Windows Vista and later Windows version that the first line processed by FOR is already the line with the value of interest. But the first processed line on Windows XP is the third line which is an empty line. Empty lines are always ignored by FOR.
So the next line processed on Windows XP by FOR is the line with the registry key. It is split up into substrings using the default delimiters normal space and horizontal tab which means here that HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows is assigned to the specified loop variable I and NT\CurrentVersion to next loop variable according to ASCII table because of option tokens=1,2*.
Therefore on Windows XP the IF condition is executed to case-insensitive compare the string assigned to loop variable I with ProductName which evaluates to false in this case.
Then the fifth line of reg output on Windows XP is processed like the third line of reg output on Windows Vista and later Windows versions.
The line with the value of interest is split up into three substrings. The first space/tab delimited string ProductName is assigned to specified loop variable I. The second space/tab delimited string REG_SZ is assigned to loop variable J. The rest of the line after the spaces/tabs after REG_SZ is assigned completely with the spaces to next but one loop variable K because of * at end of option string tokens=1,2* after 2.
The IF condition is true for that line and so the string value of interest is assigned to the environment variable WindowsProduct.
The last empty line is again ignored by FOR.
So finally the environment variable WindowsProduct is defined with the string value of interest if found at all in Windows registry.
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.
for /?
if /?
reg /?
reg query /?
set /?

Batch File Check for String in Other File

I have a batch file that writes a line with an ip and a name for the ip in the etc/hosts file. Is there a way to check if this line already exists? Or alternatively just see if a word exists in the file?
edit:
want something like if string exists move on but if not echo
initial code
findstr "mystring" "C:\Windows\System32\drivers\etc\hosts" >nul 2>&1
if errorlevel 1 echo 111.222.333.444 mystring>>%systemroot%\SYSTEM32\DRIVERS\ETC\HOSTS
Solved: with suggested enhancements
findstr /V "^#" "C:\Windows\System32\drivers\etc\hosts" | findstr /ILC:"mystring" >nul 2>&1 ||^
(echo 111.222.333.444 mystring>>%systemroot%\SYSTEM32\DRIVERS\ETC\HOSTS)
can ignore commented out lines
can search for case-insensitive string
will write a string if string not found
I suggest following batch file code for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "HostsFile=%SystemRoot%\System32\drivers\etc\hosts"
if not "%ProgramFiles(x86)%" == "" if exist %SystemRoot%\Sysnative\cmd.exe set "HostsFile=%SystemRoot%\Sysnative\drivers\etc\hosts"
if not exist %HostsFile% goto AppendData
%SystemRoot%\System32\findstr.exe /I /L /C:"mystring" %HostsFile% >nul
if not errorlevel 1 goto EndBatch
%SystemRoot%\System32\findstr.exe /R /V "$" %HostsFile% >nul
if not errorlevel 1 echo/>>%HostsFile%
:AppendData
>>%HostsFile% echo 111.222.33.44 mystring
:EndBatch
endlocal
The third line defines the environment variable HostsFile with standard file path which is right on batch file being executed on 32-bit Windows by 32-bit cmd.exe or on 64-bit Windows by 64-bit cmd.exe in directory %SystemRoot%\System32.
The fourth line takes into account the Windows File System Redirector according to WOW64 Implementation Details. The batch file is executed on 64-bit Windows if there is defined an environment variable with name ProgramFiles(x86) with a non-empty value. But the batch file is executed by 32-bit cmd.exe in directory %SystemRoot%\SysWOW64 if there is %SystemRoot%\Sysnative\cmd.exe. The redirector Sysnative does not exist for 64-bit applications. In this case the file hosts must be referenced from within 32-bit environment on 64-bit Windows with using the Sysnative redirector in file path.
Next is checked if the file hosts exists at all. If the file does not exist, the data line to append can be directly written to the file without any further checks whereby the file hosts is created in this case.
Otherwise the command FINDSTR is used to search case-insensitive with a literally interpreted search string for mystring with redirecting the perhaps found line(s) to device NUL. FINDSTR exits with value 0 if there is at least one positive match and with value 1 if the searched string could not be found on any line.
if not errorlevel 1 means IF exit code is NOT GREATER OR EQUAL 1, or in other words LOWER THAN 1, or in this case EQUAL 0 because of FINDSTR never exits with a negative value as nearly all applications and commands. So if this condition is true, the file hosts contains at least once the searched string and nothing to change on file.
Otherwise FINDSTR is used once more to search this time with a regular expression for end of line and to output all lines not having a line ending because of option /V. So if last line in file hosts has no line ending, FINDSTR exits with value 0 because of having output one line with no line ending whereby this output is redirected to device NUL.
A line ending is appended to file hosts if FINDSTR exited with value 0 because of file hosts ends with no line ending before appending next the data line to add to this file.
The code above does not work if the batch file is not executed with elevated permissions of a local administrator or the file hosts has read-only attribute set or is otherwise protected against modification by a script.
BTW: An octet of an IPv4 address cannot be greater than 255. So 111.222.333.444 is a terrible example for an IPv4 address added to file hosts because of being an invalid IPv4 address.
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.
echo /?
endlocal /?
findstr /?
goto /?
if /?
set /?
setlocal /?
See also DosTips forum topic: ECHO. FAILS to give text or blank line - Instead use ECHO/

How to add a registry key with default value containing double quotes and percent sign?

I can't run successfully a batch file with this content:
REG ADD HKEY_CLASSES_ROOT\hlpfile\shell\compress\command /d "compact.exe /C \"%1\"" /f
REG ADD HKEY_CLASSES_ROOT\hlpfile\shell\uncompress\command /d "compact.exe /U \"%1\"" /f
It results in output of the error message:
Error: Invalid command-line parameters.
I want to create context menu elements and specify actions on Windows XP SP2:
[HKEY_CLASSES_ROOT\hlpfile\shell\compress]
[HKEY_CLASSES_ROOT\hlpfile\shell\compress\command]
#="compact.exe /C \"%1\""
[HKEY_CLASSES_ROOT\hlpfile\shell\uncompress]
[HKEY_CLASSES_ROOT\hlpfile\shell\uncompress\command]
#="compact.exe /U \"%1\""
What is wrong with the two command lines in batch file?
Use following to overwrite the default value of each registry key or to create each registry key and add the default value from command line:
REG ADD HKEY_CLASSES_ROOT\hlpfile\shell\compress\command /ve /d "\"C:\Full Path\compact.exe\" /C \"%1\"" /f
REG ADD HKEY_CLASSES_ROOT\hlpfile\shell\uncompress\command /ve /d "\"C:\Full Path\compact.exe\" /U \"%1\"" /f
Doing the same from within a batch file requires:
#echo off
%SystemRoot%\System32\reg.exe ADD HKEY_CLASSES_ROOT\hlpfile\shell\compress\command /ve /d "\"C:\Full Path\compact.exe\" /C \"%%1\"" /f >nul
%SystemRoot%\System32\reg.exe ADD HKEY_CLASSES_ROOT\hlpfile\shell\uncompress\command /ve /d "\"C:\Full Path\compact.exe\" /U \"%%1\"" /f >nul
To add a registry value and not only a registry key it is always necessary to specify either /ve for the default value of the key or /v "Name of Value" plus the type of the registry value and of course the value to assign to the registry value.
In a batch file a percent sign % must be escaped with an additional percent sign for being interpreted as literal character by Windows command processor parsing the command line before executing the command, application or script. The reason is that % has a special meaning in batch files as it can be seen on running in a command prompt window:
call /? which outputs the help for command CALL explaining how to reference batch file arguments by using percent sign and an argument number without or with one or more modifiers or a percent sign and an asterisk to reference all arguments except argument 0;
for /? which outputs the help for command FOR explaining how to reference a loop variable with one percent sign on Windows command line or two percent signs in a batch file and the loop variable character without or with one or more modifiers;
set /? which outputs the help for command SET explaining how to reference environment variables by enclosing the variable name withing one percent sign on each side for immediate expansion on parsing command line or entire command block or with one exclamation mark on each side for delayed expansion if delayed environment variable expansion is enabled at all.
Please note that command REG parses the arguments different to most other console applications or internal commands of cmd.exe. A double quote " is not interpreted as end of argument string if there is a backslash left to the double quote. In this case the double quote is interpreted as literal character and the backslash left to it as escape character for the double quote. It is necessary to escape a backslash at end of a string value with one more backslash to add the data string correct.
Example:
reg add HKCU\Environment /v "Please Delete" /t REG_SZ /d "Please delete this variable with a backslash \ inside and ending with a backslash\\"
This command adds the environment variable Please Delete with string value Please delete this variable with a backslash \ inside and ending with a backslash\ to persistent list of current user environment variables. A backslash inside the data value string must not be escaped.
Please note that environment variables should be added with command SETX to Windows registry and not with command REG as done by the example above if %SystemRoot%\System32\setx.exe exists and the value of the environment variable is not longer than 1024 characters.

Resources