如何从批处理脚本中获取注册表项的值?
Posted
技术标签:
【中文标题】如何从批处理脚本中获取注册表项的值?【英文标题】:How can I get the value of a registry key from within a batch script? 【发布时间】:2010-10-01 12:06:00 【问题描述】:我需要使用 REG QUERY 命令来查看键的值,并使用此命令将结果设置为变量:
FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "KeyName" /v ValueName') DO SET Variable=%%B
但如果密钥不存在,我会在控制台中显示错误。我需要隐藏这个错误!我尝试在命令后放置一个 2>nul 来停止 stderr,但如果我只调用命令,这将有效:
REG QUERY "KeyName" /v ValueName 2>nul
如果我像这样将它放入 FOR 命令中:
FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "KeyName" /v ValueName') DO SET Variable=%%B 2>nul
显示错误。 那么有谁知道如何隐藏错误?或者也许另一个命令也可以查看密钥是否存在?
谢谢
PS:我使用的是 Windows XP
【问题讨论】:
【参考方案1】:这对我有用:
@echo OFF
setlocal ENABLEEXTENSIONS
set KEY_NAME="HKEY_CURRENT_USER\Software\Microsoft\Command Processor"
set VALUE_NAME=DefaultColor
FOR /F "usebackq skip=4 tokens=1-3" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO (
set ValueName=%%A
set ValueType=%%B
set ValueValue=%%C
)
if defined ValueName (
@echo Value Name = %ValueName%
@echo Value Type = %ValueType%
@echo Value Value = %ValueValue%
) else (
@echo %KEY_NAME%\%VALUE_NAME% not found.
)
usebackq
是必需的,因为REG QUERY
的命令使用双引号。
skip=4
忽略所有输出,除了具有值名称、类型和值的行(如果存在)。
2^>nul
防止出现错误文本。 ^
是转义字符,可让您将>
放入for
命令中。
当我按照给定的方式运行上面的脚本时,我得到这个输出:
Value Name = DefaultColor
Value Type = REG_DWORD
Value Value = 0x0
如果我将VALUE_NAME
的值更改为BogusValue
,那么我会得到:
"HKEY_CURRENT_USER\Software\Microsoft\Command Processor"\BogusValue not found.
【讨论】:
在Windows 7中,我需要使用skip=2
这很好用,只是我发现我需要将“skip=4”更改为“skip=2”。 Windows 7 x64
当前解决方案在值包含空格时出现问题 - 要解决此问题,请为最后一个标记使用通配符:FOR /F "usebackq skip=2 tokens=1-2*
HKLM\Software
有 32/64 位 版本。使用/reg:64
和/reg:32
访问适当的树。
使用for /f "usebackq tokens=1-2*" %%a IN ('^(reg query %KEY_NAME% /v %VALUE_NAME% ^| find "%VALUE_NAME%"^) 2^>nul')
怎么样?除非 KEY_NAME 以这种方式包含 VALUE_NAME,否则无需担心 reg.exe 在值之前打印多少行。【参考方案2】:
谢谢,我只需要使用:
SETLOCAL EnableExtensions
然后放一个:
2^>nul
进入 FOR 命令中调用的 REG QUERY。 再次非常感谢! :)
【讨论】:
【参考方案3】:对于 Windows 7(专业,64 位 - 不能代表其他人)我看到 REG 不再吐出
! REG.EXE VERSION 3.0
就像在 XP 中一样。所以上面需要修改才能使用
skip=2
而不是 4 - 如果您希望脚本可移植,这会使事情变得混乱。虽然它更加重量级和复杂,但基于 WMIC 的解决方案可能会更好。
【讨论】:
【参考方案4】:出于某种原因,Patrick Cuff 的代码在我的系统 (Windows 7) 上无法运行,这可能是由于 tryToBeClever 的评论。稍微修改一下就可以了:
@echo OFF
setlocal ENABLEEXTENSIONS
set KEY_NAME=HKEY_CURRENT_USER\Software\Microsoft\Command Processor
set VALUE_NAME=DefaultColor
FOR /F "tokens=1-3" %%A IN ('REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul') DO (
set ValueName=%%A
set ValueType=%%B
set ValueValue=%%C
)
if defined ValueName (
@echo Value Name = %ValueName%
@echo Value Type = %ValueType%
@echo Value Value = %ValueValue%
) else (
@echo %KEY_NAME%\%VALUE_NAME% not found.
)
【讨论】:
【参考方案5】:基于tryToBeClever解决方案(我碰巧也偶然发现并在找到它之前通过反复试验修复了自己),我还建议将reg query
的结果输出传递给find
以过滤不需要的行由于! REG.EXE VERSION x.y
不一致。 find
过滤和tokens
调整还允许准确选择我们想要的(通常是值)。还添加了引号以避免键/值名称包含空格的意外结果。
当我们只对获取值感兴趣时提出的最终结果:
@echo off
setlocal ENABLEEXTENSIONS
set KEY_NAME=HKCU\Software\Microsoft\Command Processor
set VALUE_NAME=DefaultColor
for /F "usebackq tokens=1,2,*" %%A IN (`reg query "%KEY_NAME%" /v "%VALUE_NAME%" 2^>nul ^| find "%VALUE_NAME%"`) do (
echo %%C
)
使用find
的一个潜在警告是,在发生错误时由reg
设置的错误级别现在被混淆了,因此应该只对已知存在和/或在先前验证之后的密钥使用这种方法。
在键名还包含值名的情况下(如HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion
和CurrentVersion
的情况),可以进行微小的额外优化(添加skip=1
以避免处理第一行输出)但消除了大部分灵活性,因此只能在特定用例中使用。
【讨论】:
它不支持带空格的值。为此对代币进行了微调。感谢您指出这一点!【参考方案6】:@echo off
setlocal ENABLEEXTENSIONS
set KEY_NAME=HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\awhost32.exe
set VALUE_NAME=Path
for /F "usebackq tokens=3" %%A IN (`reg query "%KEY_NAME%" /v "%VALUE_NAME%" 2^>nul ^| find "%VALUE_NAME%"`) do (
echo %%A
)
如何处理 %%A 变量中的空格?这导致 C:\Program。实际路径是 C:\Program Files\Symantec\pcAnywhere。
【讨论】:
【参考方案7】:@echo off
setlocal ENABLEEXTENSIONS
set KEY_NAME=HKLM\SOFTWARE\Wow6432Node\Acme Software Inc\Common
set VALUE_NAME=InstallDir
FOR /F "tokens=2*" %%A IN ('REG.exe query "%KEY_NAME%" /v "%VALUE_NAME%"') DO (set pInstallDir=%%B)
echo %pInstallDir%
这在 Win7 中对我有用,其中键有空格,值也有空格。 所以将上面的内容保存在c:\temp 中作为test.bat,打开一个cmd 窗口并运行它。
C:\temp>测试
C:\Program Files (x86)\acme Software Inc\APP\
【讨论】:
【参考方案8】:如果值包含空格,则此方法有效:
FOR /F "skip=2 tokens=1,2*" %%A IN ('REG QUERY "%KEY_NAME%" /v "%VALUE_NAME%" 2^>nul') DO (
set ValueName=%%A
set ValueType=%%B
set ValueValue=%%C
)
if defined ValueName (
echo Value Name = %ValueName%
echo Value Type = %ValueType%
echo Value Value = %ValueValue%
) else (
@echo "%KEY_NAME%"\"%VALUE_NAME%" not found.
)
【讨论】:
【参考方案9】:这适用于我在 Windows 7 上包含空格的变量:
FOR /F "usebackq tokens=3*" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\Software\SomeAPP" /v ValueName`) DO (
set appdir=%%A %%B
)
ECHO %appdir%
变量A
包含第一个空格之前的所有数据,B
- ValueName 的其余部分(包括更多空格),所以appdir = ValueName
【讨论】:
3*
对于确保整个 reg 值进入 %%B
很重要
我收到此代码错误。必须用引号括起来:set appdir="%%A %%B"
明确一点,如果值中没有空格,“%%A %%B”返回一个以空格结尾的值。
实际上使用tokens=2*
和SET appdir=%%B
会更安全,因为路径中的第一个空格可能与其他空格相邻(例如,C:\This is a weird path
)。【参考方案10】:
echo Off
setlocal ENABLEEXTENSIONS
set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup"
set VALUE_NAME=release
REG QUERY %KEY_NAME% /S /v %VALUE_NAME%
endlocal
点把\放在KEY_NAME的末尾
【讨论】:
这是一个过于复杂的解决方案。如果您只使用 /v %VALUE_NAME%,输出会更好【参考方案11】:这个单线与您最初的尝试几乎相同,只是添加了一些内容。它适用于包括空格的路径,并且即使未找到密钥(并隐藏错误)也适用于 XP 和 Windows 7。如果密钥不存在,%fn%
将为空。本例获取当前桌面背景文件名:
for /f "tokens=2*" %%a in ('reg query "HKEY_CURRENT_USER\Control Panel\Desktop" /v Wallpaper 2^>^&1^|find "REG_"') do @set fn=%%b
此命令使用tokens=2*
和%%a
作为循环变量,但使用%%b
来正确处理空格。使用tokens=2*
时,循环变量%%a
被赋予第二个标记(在本例中为REG_SZ
)中的值,%%b
被赋予下一组分隔符之后的行的剩余部分,包括所有内部分隔符。这意味着%%b
将正确复制分隔符——即使多个分隔符聚集在一起。例如,该值可能是C:\A weird path\blah.png
。这种读取值的技术将正确保留C:\A
和weird
之间的两个空格。
【讨论】:
所有版本的 windows 都可以使用 find 吗?为了安全起见,我会切换到 findstr。【参考方案12】:这里有很棒的解决方案。
作为解决方案@Patrick Cuff 我的一点点盐并没有开箱即用;我有 2 个问题
我使用的是 Windows 7 => 改为“skip=2” 注册表值的值中有一个空格Value Value = C:\Program Files\...
这是我找到的解决方案:取 4 个令牌并将 ValueValue 设置为 %%C 和 %%D。 (感谢@Ivan!)
setlocal ENABLEEXTENSIONS
set KEY_NAME="HKEY_CURRENT_USER\Software\Microsoft\Command Processor"
set VALUE_NAME=DefaultColor
FOR /F "usebackq skip=2 tokens=1-4" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO (
set ValueName=%%A
set ValueType=%%B
set ValueValue=%%C %%D
)
if defined ValueName (
@echo Value Name = %ValueName%
@echo Value Type = %ValueType%
@echo Value Value = %ValueValue%
) else (
@echo "%KEY_NAME:"=%\%VALUE_NAME%" not found.
)
【讨论】:
这是我找到的最佳解决方案,适用于 Windows 7 64 位。感谢您的努力【参考方案13】:在使用 WMIC 时,我在 Windows XP 计算机上遇到了许多错误(例如,由于计算机上的文件损坏)。因此,imo 最好不要在代码中将 WMIC 用于 Win XP。不过,Win 7 上的 WMIC 没有问题。
【讨论】:
【参考方案14】:您可以按如下方式获取注册表项的值
@echo OFF
setlocal ENABLEEXTENSIONS
set REG_NAME="HKEY_CURRENT_USER\Software\Test"
set KEY_NAME=TestVal
FOR /F "usebackq skip=2 tokens=1-3" %%A IN (`REG QUERY %REG_NAME% /v %KEY_NAME% 2^>nul`) DO (
@echo %%A : %%C
)
pause
想知道如何添加 reg 密钥的人,这里有一个方法。
REGEDIT4
; @ECHO OFF
; CLS
; REGEDIT.EXE /S "%~f0"
; EXIT
[HKEY_CURRENT_USER\Software\Test]
"TestVal"="Succeeded"
【讨论】:
【参考方案15】:要获得注册表值的特定答案,您可以使用以下查询:
REG QUERY "Key_Name" /v "Value_Name" /s
例如: REG QUERY "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v "EnableExtensions" /s
这里 /v : 查询特定的注册表键值。
/s : 递归查询所有子键和值(如dir /s)
【讨论】:
【参考方案16】:set regVar_LocalPrjPath="LocalPrjPath"
set regVar_Path="HKEY_CURRENT_USER\Software\xyz\KeyPath"
:: ### Retrieve VAR1 ###
FOR /F "skip=2 tokens=2,*" %%A IN ('reg.exe query %regVar_Path% /v %regVar_LocalPrjPath%') DO set "VAR1=%%B"
【讨论】:
如果您获得的是 default 键 并且 windows 语言环境是法语,这将不起作用。通过这样做,您将使用空格作为分隔符,因此键名称(Default)
被命名为 (Par Defaut)
(法语),中间有一个空格,是的,所以您需要 tokens=2
而不是 tokens=3
【参考方案17】:
使用注册表:
@echo off
setlocal
::if the scrit is not ran as administrator
:: and the key does not require admin permissions
set __COMPAT_LAYER=RunAsInvoker
set "key=%~1"
set "value=%~2"
regedit /e "#.reg" "%key%"
for /f "tokens=1,* delims==" %%a in ('find """%value%""=" "#.reg"') do if "%%~b" neq "" echo %%~b
del /q #.reg
endlocal
例子:
call regreader.bat "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.0\Setup\1033\" Version
输出:
3.0.30729.4926
【讨论】:
【参考方案18】:您也可以通过单个命令行使用此解决方案:
VARIABLE=$(reg query "HKLM\REGISTRYKEYPATH" /v "REGISTRY KEY" | grep -i "REGISTRY KEY" | awk 'print $NF;')
$NF 检索最后一个字段(即注册表项值),供您参考。
【讨论】:
我不相信这会在未经修改的 Windows XP 机器上开箱即用。完成这项工作需要哪些先决条件? 我在没有任何先决条件的情况下在 Windows 10 上进行了测试。 这可以工作(我有grep
和 awk
可从 git/msys64/cygwin 获得),但是,如果值包含空格/制表符,它会中断,例如“OneDrive - CompanyName”,在这种情况下,我只会得到“CompanyName”
我最终得到了awk '$1=$2=""; print $0;'
,它将忽略前两列并打印其他所有内容以上是关于如何从批处理脚本中获取注册表项的值?的主要内容,如果未能解决你的问题,请参考以下文章