Reg query with find command and percent character in value - windows

I'm trying to determine, in a batch file, if a particular registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion /v DevicePath
in Windows contains the following value:
%SystemRoot%\inf
The code I have so far is:
reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion /v DevicePath | find "%SystemRoot%\inf"
Unfortunately %errorlevel% always returns 1 and not 0, despite several attempts at playing with the command, adding and removing %'s and escape characters. Can someone assist please? Is there a better way to determine the value of this key?

to escape the percent signs in batch files, double them:
reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion /v DevicePath |find "%%SystemRoot%%\inf"

Related

Grepping one of "reg query" result values

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

Puppet: Mixing registry keys and Variables

I am trying to create a module to configure my systems to point at a certain server. I need to change the registry key of the hostname of the server i require.
The way i have done this is, i have a 'params.pp' which is configured with the command i'd like to run. I also have a hiera value specifying the hostname. The idea is if the hostname ever changes, i just change the hiera value and the module does not need to change.
I am getting a syntax error for the reg.exe command (i'm using puppet exec). the issue is the following code;
$server_add = "reg.exe add HKLM\\SOFTWARE\\path\\to\\registry /f /v KeyName /t REG_SZ /d ${server}"
$server_query = "reg.exe query HKLM\\SOFTWARE\\path\\to\\registry /v KeyName | findstr.exe ${server}"
It wants the double quotes around the registry key path. The issue then is my puppet code cannot access find my variable '${server}'.
I've tried many combination with quotes and double quotes and seem to have no luck.
Any help would be great.
Thanks in advance.
For the double qoutes around the registry key, please use \" in your string:
$server_add = "reg.exe add \"HKLM\\SOFTWARE\\path\\to\\registry\" /f /v KeyName /t REG_SZ /d ${server}"
It will give you:
reg.exe add "HKLM\SOFTWARE\path\to\registry" /f /v KeyName /t REG_SZ /d

Registry Query - Bat file

I want to loop through all registry entries in a certain path and see if any of those match a string. I have the below bat file command:
reg query HKLM /f Software\Microsoft\Windows\CurrentVersion\Uninstall /v ProductName /s|findstr /r "abc - def (x64)"
I am using the %errorlevel% to determine the output of the above command. Expecting 0 when a registry exactly matching is found and non-zero when such a registry is not found.
However, I am getting 0 in both cases, i.e. a registry matches the string or it it doesn't.
Can you please suggest any correction to my bat command.

REG ADD a REG_MULTI_SZ Multi-Line Registry Value

To add a REG_MULTI_SZ multi-line registry value, i can do
reg.exe ADD "HKLM\path\to\registry\key" /v RegistryValue /t REG_MULTI_SZ /d "abc\0def\0"
which would add ("abc", "def").
But what if i need to add ("abc", "", "def"), i.e. an empty item in between?
Doing
reg.exe ADD "HKLM\path\to\registry\key" /v RegistryValue /t REG_MULTI_SZ /d "abc\0\0def\0"
gives me an "invalid parameter" error.
This worked for me:
REG ADD "HKLM\LOCATION" /v "Value" /t REG_MULTI_SZ /d item1\0item2 /f
or if your items have whitespace:
REG ADD "HKLM\LOCATION" /v "Value" /t REG_MULTI_SZ /d "item1"\0"item2" /f
Make sure you don't have TWO trailing "\0" separators (one is OK, with or without the trailing \0 you will get your last return character) like the example below (like I saw in a TechNet article), or you will get an "ERROR: Invalid value specified for '/d'.":
REG ADD "HKLM\LOCATION" /v "Value" /t REG_MULTI_SZ /d item1\0item2\0\0 /f
This probably isn't possible using reg add, because the data you're trying to set is improperly formed. REG_MULTI_SZ values are terminated by an empty string, so having an empty string as part of the value is not allowed.
If you really need to, and on the understanding that some software won't be able to read the key correctly, you could use reg import instead. For example, the following file creates a value with an empty string in the middle:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\software\harrytest]
"test"=hex(7):76,00,61,00,6c,00,75,00,65,00,31,00,00,00,76,00,61,00,6c,00,75,\
00,65,00,32,00,00,00,00,00,76,00,61,00,6c,00,75,00,65,00,34,00,00,00,76,00,\
61,00,6c,00,75,00,65,00,35,00,00,00,00,00
Try this:
#reg.exe add "HKCU\Software\Wirkomatron" /v "MySoftware" /d "Software1"\0"Software2"\0"Software3"\0 /t REG_MULTI_SZ /f
And now you can do it with Batch script propertly.
Just for reference.
If you just want to insert a new line then you will need to simulate it with a space in the desire empty line. If the space would have an undesired impact in what you are trying to achieve then this post is not useful for you.
reg.exe ADD "HKLM\path\to\registry\key" /v RegistryValue /t REG_MULTI_SZ /d "abc\0 \0def\0"

How to use REG_EXPAND_SZ from the commandline?

I was reading the Windows Commandline Documentation (Win+F1) about the commands that modify the Windows registry, particularly the the "reg add" command.
reg add HKCU\testfolder /t REG_EXPAND_SZ /v Stokrotka /d "%systemroot%\system32"
Now, I don't know how this was designed to work.
When I invoke the command above, the variable %systemroot% gets expanded to C:\Windows. I've tried the following not to make the variable to expand, but there is no way I could force it not to:
escaping the `%%`'s with an `%, ^, \` - doesn't work even if I use double quotes around
using the single quotes '' around the whole /d string
use `setlocal setdelayedexpansion`? sth like:
# (setlocal enabledelayedexpansion) && (reg add HKCU\testfolder /t REG_EXPAND_SZ /v Stokrotka /d "!systemroot!\system32") && (setlocal disabledelayedexpansion)
The variable 'data' (/d) field is either like ^%systemroot^% or like !systemroot! or just expands to C:\windows .
I could probably use the .reg file to accomplish my task, but I simply don't want to do it.
I thought that maybe there is something wrong with the program that I use to display the variable contents (regedit / regedt32 / reg query (commandline)), but after checking this is probably not the case.
Any ideas? I'm mainly interested how the variable value should look like in the regedit window, should it be like :"%systemroot%\system32" or "C:\windows\system32" to be properly expanded by other programs.
Regards.
From a command line, this worked for me:
reg add HKCU\testfolder /t REG_EXPAND_SZ /v Stokrotka /d ^%systemroot^%\system32
The syntax suggested by aphoria is correct, without quotes as you discovered. But you run into trouble when you need spaces in the value.
However, it is possible to mix-in quotes in the value. It looks weird, but it works:
REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /d ^%SystemRoot^%;c:\Program" Files"\Intel\DMIX;C:\bin /t REG_EXPAND_SZ
You can use quotes where needed, just not around your variables. And not right after a backslash.
Also, beware that the syntax for use in a batch file is not the same as on the command line. If you put that line into a batch file, you need to replace the "^" with another "%":
REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /d %%SystemRoot%%;c:\Program" Files"\Intel\DMIX;C:\bin /t REG_EXPAND_SZ
(cmd.exe always reminds me of Henry Spencer's quote "Those who do not understand Unix are condemned to reinvent it, poorly")
I recognize that this is an old thread, but since there doesn't seem to be an answer and I too was driven crazy by this problem, I'll share what I've come up with. It's convoluted, it's ugly, and it looks like this:
SET VAR=% SET
SET VALUE=%VAR%SystemRoot%VAR%\system32...
REG ADD HKLM... /v Test /t
REG_EXPAND_SZ /d %VALUE%
I end up with Test containing the string %SystemRoot%\system32
Edit: Should have finished testing before posting. While this worked from the command line, it failed in my command scripts. What DID work was SET VALUE=%%SystemRoot%%\system32...
We have a use in an autounattend.xml. I was first following aphoria's answer, then I had to use mivk's enhanced answer. I had it working. Then I made a small change and it stopped working. I consider this insight worth reporting, to save others lengthy frustration.
Building on previous answers, here is how to make this work in autounattend.xml:
<CommandLine>cmd.exe /c reg.exe add HKLM\ourkey /v ourvalue /t REG_EXPAND_SZ /d "our data with spaces"^%USERNAME^%"and more spaces" /f</CommandLine>
What matters is the cmd.exe /c. If you don't use cmd.exe then reg.exe still runs, but it puts literally ^% into the registry, not the desired %.
Maybe the answer by ASTX813 would work, but this seems easier to read.
There's no magic here, you must escape every % in command-line with/become: %%.
In batch file, you again must escape them, become %%%%SystemRoot%%%%. Yes, four ampersands. It's ugly, but it's the way it is, and it's pretty consistent though.
note: Using ^ to escape it as literal character might help/cleanup in one step/degree only (as long as it's not interpreted). The advantage using ^ is that you can write in command-line or batch file with identical syntax: eg. "^%SytemRoot^%", since in both environments, % treated equally as literal.
The answer is very simple. Only quote the spaces and escape the %'s.
In command line, escape the %'s with the ^.
reg add HKLM\Software\Microsoft\Command" "Processor /v AutoRun /t REG_SZ /d title" "^%username^% /f
In batch file, escape the %'s with another %.
reg add HKLM\Software\Microsoft\Command" "Processor /v AutoRun /t REG_SZ /d title" "%%username%% /f
This took me a while to figure out. In my mind, I should quote the entire string, but could not get the variable to be passed without expanding it. I broke my way of thinking by quoting spaces instead.
Please try the following:
reg add HKCU\testfolder /t REG_EXPAND_SZ /v Stokrotka /d ^%systemroot%^\system32
From a batch file you end up with problems with quotes, which you can then escape with a backslash, for example:
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\%name%" /v "UninstallString" /t REG_EXPAND_SZ /d "\"%%comspec%%\" /d /c \"%dest%\uninstall.cmd\""
without quotes
reg add HKCU\testfolder /v Biedronka /t REG_EXPAND_SZ /d "%%%^%systemroot%%%^%\system32"
with quotes
reg add HKCU\testfolder /v Biedronka /t REG_EXPAND_SZ /d "\"^%%systemroot^%%\system32\""
I finally got sick of the banner/logo on CScript and decided to prefix VBS associations with //nologo in my 'new build' batch script. This required modifying a REG_EXPAND_SZ registry entry with an environment variable and this question and its various answers were the best inspiration I could find. Here's the final script.
SET "thecmd=\""%%SystemRoot%%\System32\CScript.exe\"" //nologo \""%%1\"" %%*"
ECHO.%thecmd%
REG.exe ADD "HKEY_CLASSES_ROOT\VBSFile\Shell\Open2\Command" /ve /t REG_EXPAND_SZ /d "%thecmd%" /f
SET thecmd=
Storing the command in a variable and using \"" for " and %% for % are what allows it to work.
If you prefer a one-liner (again, from batch) you can use:
REG.exe ADD "HKEY_CLASSES_ROOT\VBSFile\Shell\Open2\Command" /ve /t REG_EXPAND_SZ /d "\""%%SystemRoot%%\System32\CScript.exe\"" //nologo \""%%1\"" %%*" /f
If you want the same functionality, don't forget to set the verb for VBSFile to Open2 so you can just double-click VBS files to run them with CScript:
REG.exe ADD "HKEY_CLASSES_ROOT\VBSFile\Shell" /ve /t REG_SZ /d "Open2" /f

Resources