将字符串数据附加到现有的REG_MULTI_SZ Windows注册表项

时间:2017-08-14 11:34:26

标签: batch-file cmd append registry

REG ADD更改整个条目。我无法让REG ADD ~工作。

Windows注册表包含多个字符串零值。这就是REG_MULTI_SZ的含义。如何附加新字符串?虽然REG ADD命令中指定了REG_MULTI_SZ,但REG ADD删除条目中先前的所有字符串,并仅在那里写入新字符串。

有人说~之前字符串意味着附加而不是覆盖。但是,我没有确切的语法。我该如何使用~

[编辑]
以下是问题的简化版本:

我有一个注册表项KEYROOT\KEY\ENTRY,其类型为 REG_MULTI_SZ 。在此条目中,有字符串零abcd\0efgh\0。我如何添加ijkl\0以使所有三个:abcd,efgh和ijkl在注册表项\ENTRY而不仅仅是ijkl

我只想使用Batch Script或Command Prompt命令执行此操作。

请注意:我已尝试使用REG进行了很多操作,但无法找到解决方案,我不确定是否有这样的解决方案。

我将非常感谢任何建议,但我想请大家专注于~的可能性。微软表示,当字符串前面有~时,该字符串被认为是附加到其他字符串而不是覆盖它们。

我尝试了很多变体,但无法获得~的正确语法。请确保提供有关如何在要附加的字符串之前使用~的信息。

我找到了解决方案。但是,尽管解决方案有效,但是将一个字符串添加到注册表项并不是一个好主意,因为Microsoft允许字符串附加十六进制数据。无论如何,这是我能够做到的:

  1. 在批处理字符串变量中读取注册表的值:
  2. FOR /F "usebackq tokens=2,* skip=2" %%G IN ('REG QUERY "Root\Key" /v Entry') DO SET EntryContents=%%H

    注意反向撇号`。

    现在,注册表项的条目位于变量EntryContents中。

    1. 将新值连接到旧值
    2. SET NewEntryContents=%EntryContents%%ContentsToBeAppended%

      变量ContentsToBeAppended已在批处理文件的其他位置设置,或者可能是参数。变量NewEntryContents包含旧注册表项条目内容的连接字符串和变量ContentsToBeApended中的字符串。

      1. NewEntryContents添加到REG ADD条目中。
      2. 同样,当条目值被读入字符串变量时,如果它们是00或其他可能超出字符范围的值,则将忽略所有十六进制内容。解决方案可能是以某种方式将带有REG的条目导出为十六进制格式的文件,然后以某种方式仅将十六进制值添加到文件中。字符串字符必须转换为十六进制值并附加到文件以及任何新的十六进制值。

        此答案提供了读取注册表项的功能,该注册表项将在字符串变量中全部读取所有字符,例如\ 0。字符串变量将获取所有字符。示例:如果注册表项包含PATH\NAME_OF_FILE\0PATH|NAME_OF_FILE,则所有这些都将读入字符串变量。 \0也是。只需连接新字符串,该字符串也可能包含\0,并将整个字符串添加回注册表。

        这里的诀窍是for /f语句,该语句跳过2行并在G中取第三行的第二个字符串,在H中取第三个字符串(重要的一行)。所有空白和*' s ,' s,dits也将被读取。

        为了使用reg add将所有空格和*等等添加回条目,请将变量NewEntryContents括在引号中:

        REG ADD "Root\Key" /v Entry /t REG_MULTI_SZ /d "%NewEntryContents%"

        希望这可能会有所帮助。

        此外,[〜]符号仅在使用REGEDIT时有效。 REGEDIT是一种更好的方法。可以在文件中保存密钥(使用十六进制),然后可以批量编辑该文件,然后可以将新编辑的密钥导回到注册表。但是很讨厌。另外,我不确定REGEDIT是否会将字符串和十六进制数据组合到文件中。

        以下是对条目可用性和空条目的检查:

        1. 检查条目是否存在:
        2. REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager" /v PendingFileRenameOperations

          IF %ERRORLEVEL% EQU 0 GOTO THEREIS

          1. for /f
          2. 之后

            SET "EntryContents"="%EntryContents: =%" IF DEFINED EntryContents GOTO NOTEMPTY

            SET行不是必需的。摆脱字符串周围的空白。无论如何,这应该由for /f完成。

            如果已定义,则检查该值。永远不会在EntryContents之前定义最佳/f

            行。我已经成功克服了批处理脚本的所有问题。

            Echo确实回显所有ASCII字符,也可以输出Unicode,但是,还有更多的问题。

            无论如何,由于问题和解决方案的数量,我无法提供更多信息但是,无论谁感兴趣,都可以阅读我所做的批处理文件:http://www.steven-stanley-bayes.com/ForceDelete.zip

3 个答案:

答案 0 :(得分:1)

精简和平均批处理文件替代OP链接的~50KB脚本:
〜接受单个参数,文件或文件夹
〜确认提示([取消]清除以前的条目)
〜基本的白痴校对(例如,不要处理%Windir%)
〜脚本将添加一个条目以右键单击 - 第一次运行时的“SendTo”菜单

Rename_On_Boot.bat

goto="Batch" /* Rename_On_Boot by AveYo v1
:RenOnBoot
set "input=%*" & call set "input=%%input:?=%%"                            &rem line below adds entry to right-click -- "SendTo" menu
if /i "_%~dp0"=="_%APPDATA%\Microsoft\Windows\SendTo\" (set .=) else copy /y "%~f0" "%APPDATA%\Microsoft\Windows\SendTo\" >nul 2>nul
if "_%1"=="_" color 4f & echo   ERROR! No input provided & ping -n 6 localhost >nul & exit /b
for %%# in ("C:\" "C:\Boot" "C:\Recovery" "%WINDIR%" "%WINDIR%\system32" "%ProgramData%" "%ProgramFiles%" "%USERPROFILE%") do (
 if /i "_%input%"=="_%%~#" color 4f & echo   ERROR! %%# is not safe to delete & ping -n 6 localhost >nul & exit /b
)
color 0B & echo   Please wait, folders might take a while .. & call cscript /nologo /e:JScript "%~f0" RenOnBoot "%input%" & exit /b
:RenOnBoot_Run_As_Admin
color 4f & echo   Asking permission to run as Admin.. & call cscript /nologo /e:JScript "%~f0" RunAsAdmin "%~f1???" & exit /b
:"Batch"
@echo off & setlocal disabledelayedexpansion & mode 96,4 & echo. & title %~nx0 by AveYo & if not exist "%~f1" goto :RenOnBoot
reg query HKEY_USERS\S-1-5-20\Environment /v temp 1>nul 2>nul && goto :RenOnBoot || goto :RenOnBoot_Run_As_Admin
:"JScript" */
function RenOnBoot(f){
  var HKLM=0x80000002, k='SYSTEM\\CurrentControlSet\\Control\\Session Manager', v='PendingFileRenameOperations';
  var reg=GetObject('winmgmts:{impersonationLevel=impersonate}!//./root/default:StdRegProv'), ws=WSH.CreateObject('WScript.Shell');  
  var confirmation=ws.Popup(" Rename on next boot? [OK]\n Clear previous entries? [Cancel]\n\n "+f,0,'Rename_On_Boot by AveYo',33);
  if (confirmation == 2) { reg.DeleteValue(HKLM, k, v); WSH.quit(); } // Clear existing entries on Cancel press and quit script
  var mtd=reg.Methods_('GetMultiStringValue').InParameters.SpawnInstance_(); mtd.hDefKey=HKLM; mtd.sSubKeyName=k; mtd.sValueName=v;
  var query=reg.ExecMethod_('GetMultiStringValue', mtd), regvalue=(!query.ReturnValue) ? query.SValue.toArray():[,], entries=[];
  var fso=new ActiveXObject('Scripting.FileSystemObject'), fn=fso.GetAbsolutePathName(f);
  entries.push('\\??\\'+fn,'\\??\\'+fn+'.ren');
  reg.CreateKey(HKLM, k); reg.SetMultiStringValue(HKLM, k, v, entries.concat(regvalue));
}
if (WSH.Arguments.length>=2 && WSH.Arguments(0)=='RenOnBoot') RenOnBoot(WSH.Arguments(1));

function RunAsAdmin(self, arguments) { WSH.CreateObject('Shell.Application').ShellExecute(self, arguments, '', 'runas', 1) }
if (WSH.Arguments.length>=1 && WSH.Arguments(0)=='RunAsAdmin') RunAsAdmin(WSH.ScriptFullName, WSH.Arguments(1));
//

Delete_On_Boot.bat

goto="Batch" /* Delete_On_Boot by AveYo v1
:DelOnBoot
set "input=%*" & call set "input=%%input:?=%%"                            &rem line below adds entry to right-click -- "SendTo" menu
if /i "_%~dp0"=="_%APPDATA%\Microsoft\Windows\SendTo\" (set .=) else copy /y "%~f0" "%APPDATA%\Microsoft\Windows\SendTo\" >nul 2>nul
if "_%1"=="_" color 4f & echo   ERROR! No input provided & ping -n 6 localhost >nul & exit /b
for %%# in ("C:\" "C:\Boot" "C:\Recovery" "%WINDIR%" "%WINDIR%\system32" "%ProgramData%" "%ProgramFiles%" "%USERPROFILE%") do (
 if /i "_%input%"=="_%%~#" color 4f & echo   ERROR! %%# is not safe to delete & ping -n 6 localhost >nul & exit /b
)
color 0B & echo   Please wait, folders might take a while .. & call cscript /nologo /e:JScript "%~f0" DelOnBoot "%input%" & exit /b
:DelOnBoot_Run_As_Admin
color 4f & echo   Asking permission to run as Admin.. & call cscript /nologo /e:JScript "%~f0" RunAsAdmin "%~f1???" & exit /b
:"Batch"
@echo off & setlocal disabledelayedexpansion & mode 96,4 & echo. & title %~nx0 by AveYo & if not exist "%~f1" goto :DelOnBoot
reg query HKEY_USERS\S-1-5-20\Environment /v temp 1>nul 2>nul && goto :DelOnBoot || goto :DelOnBoot_Run_As_Admin
:"JScript" */
function DelOnBoot(f){
  ListDir=function(src, _root,_list) {
    _root=_root || src, _list=_list || [];
    var root=fso.GetFolder(src), files=new Enumerator(root.Files), dirs=new Enumerator(root.SubFolders);
    while (!files.atEnd()) { _list.push(files.item()); files.moveNext(); }
    while (!dirs.atEnd()) { _list=ListDir(dirs.item().path, _root,_list); _list.push(dirs.item()); dirs.moveNext(); }
    return _list;
  };
  var HKLM=0x80000002, k='SYSTEM\\CurrentControlSet\\Control\\Session Manager', v='PendingFileRenameOperations';
  var reg=GetObject('winmgmts:{impersonationLevel=impersonate}!//./root/default:StdRegProv'), ws=WSH.CreateObject('WScript.Shell');  
  var confirmation=ws.Popup(" Delete on next boot? [OK]\n Clear previous entries? [Cancel]\n\n "+f,0,'Delete_On_Boot by AveYo',33);
  if (confirmation == 2) { reg.DeleteValue(HKLM, k, v); WSH.quit(); } // Clear existing entries on Cancel press and quit script
  var mtd=reg.Methods_('GetMultiStringValue').InParameters.SpawnInstance_(); mtd.hDefKey=HKLM; mtd.sSubKeyName=k; mtd.sValueName=v;
  var query=reg.ExecMethod_('GetMultiStringValue', mtd), regvalue=(!query.ReturnValue) ? query.SValue.toArray():[,], entries=[];
  var fso=new ActiveXObject('Scripting.FileSystemObject'), fn=fso.GetAbsolutePathName(f);
  if (fso.FolderExists(fn)) { var list=ListDir(fn); for (var i in list) entries.push('\\??\\'+list[i],''); }
  entries.push('\\??\\'+fn,'');
  reg.CreateKey(HKLM, k); reg.SetMultiStringValue(HKLM, k, v, entries.concat(regvalue));
}
if (WSH.Arguments.length>=2 && WSH.Arguments(0)=='DelOnBoot') DelOnBoot(WSH.Arguments(1));

function RunAsAdmin(self, arguments) { WSH.CreateObject('Shell.Application').ShellExecute(self, arguments, '', 'runas', 1) }
if (WSH.Arguments.length>=1 && WSH.Arguments(0)=='RunAsAdmin') RunAsAdmin(WSH.ScriptFullName, WSH.Arguments(1));
//

答案 1 :(得分:0)

虽然没有请求,但你可以在PowerShell中使用类似的东西:

$key = Get-Item "KEYROOT:\KEY\"
$values = $key.GetValue("ENTRY")
$values += "ijkl"
Set-ItemProperty "KEYROOT:\KEY\" "ENTRY" $values -Type MultiString

更改KEYROOT,KEY&进入正版字符串

答案 2 :(得分:0)

以下批处理文件分四个步骤完成工作:

  1. 将值导出到文件中,
  2. 使用 for 命令
  3. 提取值 子程序中的

    1. 如果值有效,则连接字符串和
    2. 最后写回来。
    3. 在此代码中,HKCU \ Software \ AITEM是注册表项,AVALUE是值的名称。最后" newstring"是您要添加到列表中的字符串。

      echo命令仅用于调试目的,可以删除。 该代码仅在密钥AITEM和值AVALUE已存在且AVALUE已在其列表中至少有一个字符串时才有效。

      @echo off
      reg query HKCU\Software\AITEM /v AVALUE > tmp.txt
      FOR /F "tokens=2,3*" %%a in (tmp.txt) do call :sub1 %%b
      del tmp.txt
      
      
      :sub1
      if %1x==x goto end
      echo %1
      REG ADD HKCU\Software\AITEM /f /v AVALUE /t REG_MULTI_SZ /d %1\0newstring
      :end
      goto :eof
      

      如果AVALUE不存在或为空,则以下代码也有效:

      @echo off
      reg query HKCU\Software\AITEM /v AVALUE > tmp.txt
      find "AVALUE" tmp.txt
      if errorlevel 1 goto sub2
      
      FOR /F "tokens=2,3*" %%a in (tmp.txt) do call :sub1 %%b
      del tmp.txt
      
      
      goto :eof
      
      :sub2
      REG ADD HKCU\Software\AITEM /f /v AVALUE /t REG_MULTI_SZ /d newstring
      goto :eof
      
      :sub1
      REG ADD HKCU\Software\AITEM /f /v AVALUE /t REG_MULTI_SZ /d %1\0newstring
      if errorlevel 1 REG ADD HKCU\Software\AITEM /f /v AVALUE /t REG_MULTI_SZ /d newstring
      goto :eof