我是一个经常修改注册表的修补匠,我讨厌不得不.reg
一个一个地单击许多文件;如何自动将.reg
文件转换为 PowerShellSet-ItemProperty
命令?
- 我找到了一个这样做的站点 [ Registry to PowerShell Converter ],但是输出不是我想要的格式;
Set-ItemProperty
我希望它使用/Remove-Item
/具有与以下完全相同的语法,仅此New-Item
而已:Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\CurrentVersion\PushNotifications] "NoToastApplicationNotification"=dword:00000001
cmd
:Reg Add "HKLM\Software\Policies\Microsoft\Windows\CurrentVersion\PushNotifications" /v "NoToastApplicationNotification" /t REG_DWORD /d 1
powershell
:Set-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\CurrentVersion\PushNotifications" -Name "NoToastApplicationNotification" -Type DWord -Value 1
- 产生预期结果的命令应该是:
"Set-ItemProperty -Path " + $path + "-Name " + $name + "-Value " + $value
- 我创建了一个 ASCII 表,其中包含在此处找到并上传到此处的信息,管理此 [输出]:
$ASCII=import-csv ".\desktop\ascii.csv" [array]$AsciiTable=0..255 | foreach-object{ $Decimal=$ASCII[$_].DEC $Hexadecimal=$ASCII[$_].HEX $Binary=$ASCII[$_].BIN $Octonary=$ASCII[$_].OCT $Symbol=$ASCII[$_].Symbol $Value=[char]$_ $Description=$ASCII[$_].Description $HTMLName=$ASCII[$_].HTMLName $HTMLNumber=$ASCII[$_].HTMLNumber [pscustomobject]@{Decimal=$Decimal;Hexadecimal=$Hexadecimal;Binary=$Binary;Octonary=$Octonary;Symbol=$Symbol;Value=$Value;Description=$Description;HTMLName=$HTMLName;HTMLNumber=$HTMLNumber} } $AsciiTable | Export-csv ".\Desktop\AsciiTable.csv"
- 我创建了一个 ASCII 表,其中包含在此处找到并上传到此处的信息,管理此 [输出]:
目前我已经管理了这个,这是不完整的,但想法是通过文件循环index
,通过正则表达式匹配为变量分配值,将类型和配置单元名更改为 PowerShell 中使用的值:
$registry=get-content $regfile
for ($i=0;$i -lt $registry.count;$i++){
$line=$registry | select-object -index $i
if ($line -match '\[' -and '\]') {
$path=$line -replace '\[|\]'
switch ($path)
{
{$path -match "HKEY_CLASSES_ROOT"} {$path=$path -replace "HKEY_CLASSES_ROOT","HKCR:"}
{$path -match "HKEY_CURRENT_USER"} {$path=$path -replace "HKEY_CURRENT_USER","HKCU:"}
{$path -match "HKEY_LOCAL_MACHINE"} {$path=$path -replace "HKEY_LOCAL_MACHINE","HKLM:"}
{$path -match "HKEY_USERS"} {$path=$path -replace "HKEY_USERS","HKU:"}
{$path -match "HKEY_CURRENT_CONFIG"} {$path=$path -replace "HKEY_CURRENT_CONFIG","HKCC:"}
}
}
else {
$name=($line | select-string -pattern "`"([^`"=]+)`"").matches.value | select-object -first 1
switch ($line)
{
{$line -match}
}
有六种注册表值类型 [ REG_SZ
, REG_BINARY
, REG_DWORD
, REG_QWORD
, REG_MULTI_SZ
, REG_EXPAND_SZ
] 并且我在文件中只看到一种DWORD
值类型.reg
,尽管我设法创建了一个包含所有类型的注册表项:
RegEdit
:
.reg
:Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AarSvc] "DependOnService"=hex(7):41,00,75,00,64,00,69,00,6f,00,73,00,72,00,76,00,00,00,\ 00,00 "Description"="@%SystemRoot%\\system32\\AarSvc.dll,-101" "DisplayName"="@%SystemRoot%\\system32\\AarSvc.dll,-100" "ErrorControl"=dword:00000001 "FailureActions"=hex:80,51,01,00,00,00,00,00,00,00,00,00,04,00,00,00,14,00,00,\ 00,01,00,00,00,10,27,00,00,01,00,00,00,10,27,00,00,01,00,00,00,10,27,00,00,\ 00,00,00,00,00,00,00,00 "ImagePath"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,\ 74,00,25,00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,73,\ 00,76,00,63,00,68,00,6f,00,73,00,74,00,2e,00,65,00,78,00,65,00,20,00,2d,00,\ 6b,00,20,00,41,00,61,00,72,00,53,00,76,00,63,00,47,00,72,00,6f,00,75,00,70,\ 00,20,00,2d,00,70,00,00,00 "ObjectName"="NT Authority\\LocalService" "RequiredPrivileges"=hex(7):53,00,65,00,49,00,6d,00,70,00,65,00,72,00,73,00,6f,\ 00,6e,00,61,00,74,00,65,00,50,00,72,00,69,00,76,00,69,00,6c,00,65,00,67,00,\ 65,00,00,00,00,00 "ServiceSidType"=dword:00000001 "Start"=dword:00000003 "Type"=dword:00000060 "UserServiceFlags"=dword:00000003 "New Value #1"=hex(b):00,00,00,00,00,00,00,00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AarSvc\Parameters] "ServiceDll"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,\ 00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,\ 41,00,61,00,72,00,53,00,76,00,63,00,2e,00,64,00,6c,00,6c,00,00,00 "ServiceDllUnloadOnStop"=dword:00000001 "ServiceMain"="ServiceMain"
如何在 a 中确定注册表类型.reg
,因为预期的最终结果是包含转换后的命令的文本文件/字符串数组/PowerShell 脚本?
- 在 a
.reg
中,我知道 type 的值REG_DWORD
写为dword
,REG_SZ
用引号括起来的纯文本,REG_QWORD
如qword
(此处所示),并且已经将注册表类型映射到其相应的 PowerShell 属性:
从上面推断的关系:REG_SZ → String REG_EXPAND_SZ → ExpandString REG_MULTI_SZ → MultiString REG_BINARY → Binary REG_DWORD → DWord REG_QWORD → QWord
switch ($line) { {$line -match '"="'} {$type="string"} {$line -match "dword"} {$type="dword"} {$line -match "qword"} {$type="qword"} {$line -match "hex\(2\)"} {$type="expandstring";break} {$line -match "hex\(7\)"} {$type="multistring";break} {$line -match "hex\(b\)"} {$type="qword";break} {$line -match "hex"} {$type="binary"} }
如何检测和解码注册表 hex babbles 以及是否有其他方法可以在 a 中写入REG_EXPAND_SZ
、REG_MULTI_SZ
和REG_BINARY
types .reg
(即分别为 as和ExpandString
type )?MultiString
Binary
- 将注册表可扩展字符串值解析为纯文本的脚本:
function parse-expandstring { PARAM ( [Parameter(ValueFromPipeline=$true, Mandatory=$true)] [System.String]$expandstring ) $AsciiTable=import-csv ".\desktop\AsciiTable.csv" [array]$hex=$expandstring -split'[\,\\]' | where {-not ([string]::IsNullOrWhiteSpace($_))} | %{$_.trimstart()} $hexadecimal=0..($hex.count-1) | where {$_ % 2 -ne 1} | foreach-object {$hex[$_]} $text=@() foreach ($hexadecima in $hexadecimal) { for ($i=0;$i -le 255;$i++) { if ($AsciiTable[$i].hexadecimal -eq $hexadecima) { $text+=$AsciiTable[$i].value } } } $text=$text -join "" $text }
Function
解析REG_QWORD
:function parse-qword { PARAM ( [Parameter(ValueFromPipeline=$true, Mandatory=$true)] [System.String]$qword ) [array]$qword=$qword -split',' $qword=for ($i=$qword.count-1;$i -ge 0;$i--) {$qword[$i]} $hexvalue=$qword -join "" $hexvalue=$hexvalue.trimstart("0") $hexvalue }
Function
解析REG_BINARY
:function parse-binary { PARAM ( [Parameter(ValueFromPipeline=$true, Mandatory=$true)] [System.String]$binary ) [array]$hex=$binary -split'[,\\]' | where {-not ([string]::IsNullOrWhiteSpace($_))} | %{$_.trimstart()} $hex=$hex -join "" $hex }
Function
解析REG_MULTI_SZ
:function parse-multistring { PARAM ( [Parameter(ValueFromPipeline=$true, Mandatory=$true)] [System.String]$multistring ) $AsciiTable=import-csv ".\desktop\AsciiTable.csv" [array]$hex=$multistring -split'[\,\\]' | where {-not ([string]::IsNullOrWhiteSpace($_))} | %{$_.trimstart()} $hexadecimal=0..($hex.count-1) | where {$_ % 2 -ne 1} | foreach-object {$hex[$_]} $text=@() foreach ($hexadecima in $hexadecimal) { for ($i=0;$i -le 255;$i++) { if ($AsciiTable[$i].hexadecimal -eq $hexadecima) { if ($i -ne 0) {$text+=$AsciiTable[$i].value} else {$text+="\0"} } } } $text=$text -join "" $text }
脚本几乎完成了,已经创建了Remove-Item
, New-Item
, 和Remove-ItemProperty
switch 条件;现在,难题的最后一部分是编写一个匹配值的正则表达式。完成后,我将在此处发布它作为答案。
- 伪代码:
if $line match [ and ]->$line match [-HKEY -> Remove-Item else $registry[$i+1] eq ""->New-Item elseif $line match "=-" -> Remove-ItemProperty
- 我创建了一个 ASCII 哈希表用作字典:
$asciihex=@{} 0..255 | % { $number=$_ [string]$hex=$number.tostring('x') if ($hex.length -eq 1) {$hex='{1}{0}' -f $hex,'0'} $char=[char]$number $asciihex.add($hex,$char) }
- 要在给定代码点查找字符:
# Change: $asciihex.'00' # to: $asciihex.'ff'
- 要在任何代码点查找字符:
# Don't use $asciihex to print it $asciihex.$codepoint
- 要在给定代码点查找字符:
要从行中 grep 值,请使用-replace $name+$type
获取值。
最终版本:
This is the final version, based on my previous script and the script provided by SimonS. The script is truly complete, all bugs fixed, it can correctly parse all 6 registry value types:
REG_SZ
,REG_DWORD
,REG_QWORD
,REG_BINARY
,REG_MULTI_SZ
andREG_EXPAND_SZ
, converts each[HKEY_*
line to aNew-Item
line, each[-HKEY_*
to aRemove-Item
line, each"([^"=]+)"=-
line to aRemove-ItemProperty
line, and each"([^"=]+)"=
line to an appropriateSet-ItemProperty
line based on the property type. It accepts an inputted path, automatically detect whether the path points to a file or a folder, if a file with extension of .reg, it outputs converted commands to a file at the parent folder of the file with${filename}_reg.ps1
as its filename; If a folder, converts all .reg files inside that folder, and outputs a${filename}_reg.ps1
file for each .reg file to that folder, and then put all_reg.ps1
commands into oneallcommands.ps1
in the folder.I made numerous tests and have confirmed it is really really working. The script is now complete. I made major improvements, used better formats, and simplified the code greatly, used better logics and made many other enhancements.
This is truly complete, to use my final version, copy paste the function into an opened powershell window, and invoke it like reg2ps1 "full\path\to\content" or save it as a .ps1 file and run it by cd $scriptdir and .\reg2ps1.ps1, then input full\path\to\content, notice you shouldn't use any quotes, or the path can't be found...
Update
I made a mistake in the code, by specifying the
-Force
parameter when usingNew-Item
, if the item already exists, it will re-create the item, emptying the item in the process, this is not what I intended, now it's fixed. By removing-Force
parameter in theNew-Item
line, trying to create an item that already exists will generate an error that tells the item exists, and will not reset the item. The error message is hidden by-ErrorAction SilentlyContinue
. If the item doesn't exist, it will be created, the item will be empty, the process will prompt a message that tells the item is created, the message is hidden by| Out-Null
.This is pretty good, but you have some errors in your conversion code.
可能值得修复