如何从批处理脚本中获取注册表项的值?

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\Software32/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\CurrentVersionCurrentVersion 的情况),可以进行微小的额外优化(添加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:\Aweird 之间的两个空格。

【讨论】:

所有版本的 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 上进行了测试。 这可以工作(我有 grepawk 可从 git/msys64/cygwin 获得),但是,如果值包含空格/制表符,它会中断,例如“OneDrive - CompanyName”,在这种情况下,我只会得到“CompanyName” 我最终得到了awk '$1=$2=""; print $0;',它将忽略前两列并打印其他所有内容

以上是关于如何从批处理脚本中获取注册表项的值?的主要内容,如果未能解决你的问题,请参考以下文章

批处理如何设置注册表项的权限

批处理文件 REG QUERY

如何使用批处理脚本从文本文件中获取唯一字符串

如何从批处理脚本中获取特定的标准输出以重定向到文本文件

批处理脚本从所有用户获取计算机上的所有打印机

如何获取注册表项的值,并且仅使用 powershell 获取值