a) is that the likely reason why my script isn't working
I dunno. Sounds plausible.
b) if so is there a regedit alternative
You can query registry values with WMI and the StdRegProv class.
Trying to keep it nice and simple.
Sorry. It is neither nice nor simple.
I've had to simulate reg.exe
using WMI queries in the past to query remote registries. I hacked together a :getRegValue
function that automates much of this. Run this and see whether it will work for what you have in mind.
@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
As additional food for thought, wmic.exe
supports remote queries with the following syntax:
wmic /node:remotePC /user:domain\remoteAdmin /password:password verbs...
Rather than having each user run your script at logon, you could use the remote switches to query all machines in batch.
Partly as an academic exercise and partly to head off anyone who might be thinking "You should use PowerShell", I rewrote the :getRegValue
function to invoke PowerShell hybrid code. Unfortunately, querying the registry via WMI with PowerShell is still complicated. Although the string operations and object retrieval are easier, the marginally more economical code doesn't quite justify the added execution time.
<# : 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 }
}
Just because I felt like a challenge, I decided to try a third version employing JScript hybrid code this time. Believe it or not, this is the fastest of all three methods.
@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);