在 GPO 中禁用注册表编辑工具时使用 Reg 查询? MS Office 版本查询

Use Reg Query whilst Registry Editing Tools Disabled in GPO? MS Office Version Lookup

大家好,

所以我写了一个简单的 .bat 文件,我打算在用户启动时调用它来获取 MS Office 版本。对管理员进行了很好的测试,但不幸的是,对标准用户而言并非如此。我怀疑这是因为我们有: 阻止访问注册表编辑工具 GPO 中的设置,虽然从 运行 禁用注册表编辑器,但静音设置为 'no'。

所以我的问题是 a) 是我的脚本无法运行的可能原因,b) 如果是的话,是否有 regedit 替代方案。努力保持它的美观和简单。

代码如下:

@echo off

reg query HKEY_CLASSES_ROOT\Access.Application\CurVer
if errorlevel 1 goto five

for /f "tokens=3" %%i in ('reg query HKEY_CLASSES_ROOT\Access.Application\CurVer') do (
  if %%i equ Access.Application.15 goto one
  if %%i equ Access.Application.14 goto two
  if %%i equ Access.Application.12 goto three
  if %%i equ Access.Application.11 goto four
  goto five
)

:one REM 2013 Pro
echo %computername%,Office 2013 Pro" >>\SERVERNAME\bslogs$\officeVersions.csv
exit
:two REM 2010 Pro
echo %computername%,Office 2010 Pro >>\SERVERNAME\bslogs$\officeVersions.csv
exit
:three REM 2007 Pro
echo %computername%,Office 2007 Pro" >>\SERVERNAME\bslogs$\officeVersions.csv
exit
:four REM 2003 Pro
echo %computername%,Office 2003 Pro" >>\SERVERNAME\bslogs$\officeVersions.csv
exit

:five REM Not Pro Verion
reg query HKEY_CLASSES_ROOT\Word.Application\CurVer
if errorlevel 1 goto ten

for /f "tokens=3" %%i in ('reg query HKEY_CLASSES_ROOT\Word.Application\CurVer') do (
  if %%i equ Word.Application.15 goto six
  if %%i equ Word.Application.14 goto seven
  if %%i equ Word.Application.12 goto eight
  if %%i equ Word.Application.11 goto nine
  goto ten
)

:six REM 2013 STD
echo %computername%,Office 2013 Std" >>\SERVERNAME\bslogs$\officeVersions.csv
exit
:seven REM 2010 STD
echo %computername%,Office 2010 Std" >>\SERVERNAME\bslogs$\officeVersions.csv
exit
:eight REM 2007 STD
echo %computername%,Office 2007 Std" >>\SERVERNAME\bslogs$\officeVersions.csv
exit
:nine REM 2003 STD
echo %computername%,Office 2003 Std" >>\SERVERNAME\bslogs$\officeVersions.csv
exit

:ten REM no idea
echo %computername%,????" >>\SERVERNAME\bslogs$\officeVersions.csv exit

非常感谢, 马丁

a) is that the likely reason why my script isn't working

我不知道。听起来很有道理。

b) if so is there a regedit alternative

您可以使用 WMI 和 StdRegProv class.

查询注册表值

Trying to keep it nice and simple.

对不起。既不好看也不简单

我过去不得不模拟 reg.exe 使用 WMI 查询来查询远程注册表。我一起破解了一个 :getRegValue 函数,可以自动执行其中的大部分操作。 运行 看看它是否符合您的想法。

@echo off
setlocal

call :getRegValue accessVer HKCR\Access.Application\CurVer\
echo Result: %accessVer%

call :getRegValue shell "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell"
echo Result: %shell%

goto :EOF

:getRegValue <return_var> <root\path\valname>
setlocal enabledelayedexpansion
rem // constants
set "hive[HKCR]=&H80000000"
set "hive[HKCU]=&H80000001"
set "hive[HKLM]=&H80000002"
set "hive[HKU]=&H80000003"
set "hive[HKCC]=&H80000005"

set "type[1]=GetStringValue"
set "type[2]=GetExpandedStringValue"
set "type[3]=GetBinaryValue"
set "type[4]=GetDWORDValue"
set "type[7]=GetMultiStringValue"
set "type[11]=GetQWORDValue"

SET "wmic=wmic /namespace:\root\default class stdregprov call"

rem // split %~2 into hive, path, leaf
set "regpath=%~2"
if "%regpath:~-1%"=="\" set "regpath=%regpath%(Default)"
set hive=%regpath:\=&rem;%
set "regpath=!regpath:%hive%\=!"
set "leaf=%regpath%"
:leaf
set "leaf=%leaf:*\=%"
if not "%leaf%"=="%leaf:\=%" goto leaf
set "regpath=!regpath:\%leaf%=!"

set "hive=!hive[%hive%]!"

rem // get data type of leaf (default: string)
set "method=%type[1]%"
for %%I in (names types nameidx) do set "%%I="

2>NUL (
    for /f "tokens=2 delims={}" %%I in (
        '%wmic% EnumValues hDefKey^="%hive%" sSubkeyName^="%regpath:\=\%"^
        ^| find "= {"'
    ) do (
        if not defined names (set "names=%%I") else set "types=%%I"
    )
)

if defined names (
    for %%n in (names types) do (
        set idx=0
        for %%I in (!%%n!) do (
            if defined nameidx (
                if !idx! equ !nameidx! set "method=!type[%%~I]!"
            ) else if /i "%%~I"=="%leaf%" (
                set "nameidx=!idx!"
            )
            set /a idx += 1
        )
    )
)

if /i "%leaf%"=="(Default)" set "leaf="

rem // get data value of leaf
2>NUL (
    for /f "delims=" %%I in (
        '%wmic% %method% hDefKey^="%hive%" sSubkeyName^="%regpath:\=\%"^
        sValueName^="%leaf%" ^| findstr "[su]Value"'
    ) do (
        for %%# in (%%I) do set "ret=%%~#"
    )
)
endlocal & set "%~1=%ret%" & goto :EOF

作为额外的思考,wmic.exe 支持使用以下语法的远程查询:

wmic /node:remotePC /user:domain\remoteAdmin /password:password verbs...

与其让每个用户 运行 在登录时使用您的脚本,不如使用远程开关批量查询所有计算机。


部分是作为学术练习,部分是为了阻止任何可能有这种想法的人 "You should use PowerShell",我重写了 :getRegValue 函数以调用 PowerShell 混合代码。遗憾的是,使用 PowerShell 通过 WMI 查询注册表仍然很复杂。虽然字符串操作和对象检索更容易,但稍微更经济的代码并不能完全证明增加的执行时间是合理的。

<# : regval.bat
@echo off
setlocal

call :getRegValue accessVer HKCR\Access.Application\CurVer\
echo Result: %accessVer%

call :getRegValue shell "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell"
echo Result: %shell%

goto :EOF

:getRegValue <return_var> <root\path\valname>
setlocal
set "regpath=%~2"

for /f "delims=" %%I in (
    'powershell -noprofile -noninteractive "iex (gc \"%~f0\" | out-string)"'
) do (
    endlocal
    set "%~1=%%~I"
)
goto :EOF
: powershell hybrid code #>

$hiveConst = @{
    "HKCR" = 2147483648
    "HKCU" = 2147483649
    "HKLM" = 2147483650
    "HKU" = 2147483651
    "HKCC" = 2147483653
}

# http://www.vistax64.com/powershell/10160-powershell-remote-registry-access-via-wmi.html
$reg = gwmi -List -Namespace root\default | ?{ $_.Name -eq "StdRegProv" }

# split $env:regpath into $hive, $regpath, $leaf
$regpath = $env:regpath -split "\"
$hive = $hiveConst[$regpath[0]]
$leaf = $regpath[$regpath.length - 1]
if ($leaf) {
    $regpath = $regpath[1..($regpath.length - 2)] -join "\"
} else {
    $regpath = $regpath[1..($regpath.length - 1)] -join "\"
}

if ($leaf -match "^\(Default\)$") { $leaf = "" }

# get data type of leaf (default: string)
$method = 1
$res = $reg.EnumValues($hive, $regpath)
for ($i = 0; $i -lt $res.sNames.length; $i++) {
    if ($res.sNames[$i] -eq $leaf) {
        $method = $res.Types[$i]
    }
}

# get data value of leaf
switch ($method) {
    1 { $reg.GetStringValue($hive, $regpath, $leaf).sValue; break }
    2 { $reg.GetExpandedStringValue($hive, $regpath, $leaf).sValue; break }
    3 { $reg.GetBinaryValue($hive, $regpath, $leaf).uValue; break }
    4 { $reg.GetDWORDValue($hive, $regpath, $leaf).uValue; break }
    7 { $reg.GetMultiStringValue($hive, $regpath, $leaf).sValue; break }
    11 { $reg.GetQWORDValue($hive, $regpath, $leaf).uValue; break }
}

只是因为我觉得这是一个挑战,所以我决定这次尝试使用 JScript 混合代码的第三个版本。信不信由你,这是所有三种方法中最快的。

@if (@CodeSection == @Batch) @then
@echo off & setlocal

call :getRegValue accessVer HKCR\Access.Application\CurVer\
echo Result: %accessVer%

call :getRegValue shell "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell"
echo Result: %shell%

goto :EOF

:getRegValue <return_var> <root\path\valname>
for /f "delims=" %%I in ('cscript /nologo /e:JScript "%~f0" "%~2"') do set "%~1=%%~I"
goto :EOF

@end // end batch / begin JScript hybrid code

function reg(strMethod, objParams) {
    try {
        var winmgmts = GetObject('winmgmts:root\default'),
            StdRegProv = winmgmts.Get('StdRegProv');
            params = StdRegProv.Methods_(strMethod).InParameters.SpawnInstance_();

        for (var i in objParams) params[i] = objParams[i];
        return winmgmts.ExecMethod('StdRegProv', strMethod, params);
    }
    catch(e) { return {'sValue':''} }
};

var hiveConst = {
        "HKCR" : 2147483648,
        "HKCU" : 2147483649,
        "HKLM" : 2147483650,
        "HKU" : 2147483651,
        "HKCC" : 2147483653
    },
    methodConst = {
        "1" : "GetStringValue",
        "2" : "GetExpandedStringValue",
        "3" : "GetBinaryValue",
        "4" : "GetDWORDValue",
        "7" : "GetMultiStringValue",
        "11" : "GetQWORDValue"
    },
    regpath = WSH.Arguments(0).split('\'),
    hive = hiveConst[regpath.shift()],
    leaf = regpath.pop(),
    regpath = regpath.join('\');

if (/^\(Default\)$/.test(leaf)) leaf = '';

// get data type of leaf (default: string)
try {
    var params = {'hDefKey': hive, 'sSubKeyName': regpath},
        res = reg('EnumValues', params),
        sNames = res.sNames.toArray(),
        Types = res.Types.toArray();

    for (var i in sNames) {
        if (sNames[i] == leaf) var method = methodConst[Types[i]];
    }
}
catch(e) { var method = methodConst[1] }

// get and output data value of leaf
var params = {'hDefKey': hive, 'sSubKeyName': regpath, 'sValueName': leaf},
    res = reg(method, params);
WSH.Echo(res.sValue || res.uValue);