我是一名修补匠,经常对注册表进行修改,我讨厌逐个点击多个.reg
文件;如何将.reg
文件自动转换为 PowerShellSet-ItemProperty
命令?
- 我找到了一个可以这样做的网站[注册表到 PowerShell 转换器],但是输出不是我想要的格式;我希望它具有与下面完全相同的语法,使用
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"
如何确定注册表类型.reg
,因为预期的最终结果是包含转换命令的文本文件/字符串数组/ PowerShell 脚本?
- 在中
.reg
,我知道类型的值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"} }
我如何检测和解码注册表十六进制混乱信息,是否有其他方法可以在 a 中写入REG_EXPAND_SZ
、REG_MULTI_SZ
和类型(即分别为、和)?REG_BINARY
.reg
ExpandString
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
切换条件;现在,难题的最后一部分是编写与值匹配的正则表达式。完成后,我会将其作为答案发布在此处。
- 伪代码:
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
获取值。
答案1
最终版本:
Function reg2ps1 {
[CmdLetBinding()]
Param(
[Parameter(ValueFromPipeline=$true, Mandatory=$true)]
[Alias("FullName")]
[string]$path,
$Encoding = "utf8"
)
Begin {
$hive = @{
"HKEY_CLASSES_ROOT" = "HKCR:"
"HKEY_CURRENT_USER" = "HKCU:"
"HKEY_LOCAL_MACHINE" = "HKLM:"
"HKEY_USERS" = "HKU:"
"HKEY_CURRENT_CONFIG" = "HKCC:"
}
[system.boolean]$isfolder=$false
$addedpath=@()
}
Process {
switch (test-path $path -pathtype container)
{
$true {$files=(get-childitem -path $path -recurse -force -file -filter "*.reg").fullname;$isfolder=$true}
$false {if($path.endswith(".reg")){$files=$path}}
}
foreach($File in $Files) {
$Commands = @()
[string]$text=$nul
$FileContent = Get-Content $File | Where-Object {![string]::IsNullOrWhiteSpace($_)} | ForEach-Object { $_.Trim() }
$joinedlines = @()
for ($i=0;$i -lt $FileContent.count;$i++){
if ($FileContent[$i].EndsWith("\")) {
$text=$text+($FileContent[$i] -replace "\\").trim()
} else {
$joinedlines+=$text+$FileContent[$i]
[string]$text=$nul
}
}
foreach ($joinedline in $joinedlines) {
if ($joinedline -match '\[' -and $joinedline -match '\]' -and $joinedline -match 'HKEY') {
$key=$joinedline -replace '\[|\]'
switch ($key.StartsWith("-HKEY"))
{
$true {
$key=$key.substring(1,$key.length-1)
$hivename = $key.split('\')[0]
$key = "`"" + ($key -replace $hivename,$hive.$hivename) + "`""
$Commands += 'Remove-Item -Path {0} -Force -Recurse' -f $key
}
$false {
$hivename = $key.split('\')[0]
$key = "`"" + ($key -replace $hivename,$hive.$hivename) + "`""
if ($addedpath -notcontains $key) {
$Commands += 'New-Item -Path {0} -ErrorAction SilentlyContinue | Out-Null'-f $key
$addedpath+=$key
}
}
}
}
elseif ($joinedline -match "`"([^`"=]+)`"=") {
[System.Boolean]$delete=$false
$name=($joinedline | select-string -pattern "`"([^`"=]+)`"").matches.value | select-object -first 1
switch ($joinedline)
{
{$joinedline -match "=-"} {$commands+=$Commands += 'Remove-ItemProperty -Path {0} -Name {1} -Force' -f $key, $Name;$delete=$true}
{$joinedline -match '"="'} {
$type="string"
$value=$joinedline -replace "`"([^`"=]+)`"="
}
{$joinedline -match "dword"} {
$type="dword"
$value=$joinedline -replace "`"([^`"=]+)`"=dword:"
$value="0x"+$value
}
{$joinedline -match "qword"} {
$type="qword"
$value=$joinedline -replace "`"([^`"=]+)`"=qword:"
$value="0x"+$value
}
{$joinedline -match "hex(\([2,7,b]\))?:"} {
$value=($joinedline -replace "`"[^`"=]+`"=hex(\([2,7,b]\))?:").split(",")
$hextype=($joinedline | select-string -pattern "hex(\([2,7,b]\))?").matches.value
switch ($hextype)
{
{$hextype -eq 'hex(2)' -or $hextype -eq 'hex(7)'} {
$value=for ($i=0;$i -lt $value.count;$i+=2) {
switch ($hextype)
{
'hex(2)' {if ($value[$i] -ne '00') {[string][char][int]('0x'+$value[$i])}}
'hex(7)' {if ($value[$i] -ne '00') {[string][char][int]('0x'+$value[$i])} else {"\0"}}
}
}
$value=$value -join ""
switch ($hextype)
{
'hex(2)' {$type="expandstring"}
'hex(7)' {$type="multistring"}
}
}
'hex(b)' {
$type="qword"
$value=for ($i=$value.count-1;$i -ge 0;$i--) {$value[$i]}
$value='0x'+($value -join "").trimstart('0')
}
'hex' {
$type="binary"
$value='0x'+($value -join "")
}
}
}
}
if ($delete -eq $false) {$commands+='Set-ItemProperty -Path {0} -Name {1} -Type {2} -Value {3}' -f $key, $name, $type, $value}
}
elseif ($joinedline -match "@=") {
$name='"(Default)"';$type='string';$value=$joinedline -replace '@='
$commands+='Set-ItemProperty -Path {0} -Name {1} -Type {2} -Value {3}' -f $key, $name, $type, $value
}
}
$parent=split-path $file -parent
$filename=[System.IO.Path]::GetFileNameWithoutExtension($file)
$Commands | out-file -path "${parent}\${filename}_reg.ps1" -encoding $encoding
}
if ($isfolder -eq $true) {
$allcommands=(get-childitem -path $path -recurse -force -file -filter "*_reg.ps1").fullname | where-object {$_ -notmatch "allcommands_reg"} | foreach-object {get-content $_}
$allcommands | out-file -path "${path}\allcommands_reg.ps1" -encoding $encoding
}
}
}
$path = Read-Host "input path"
reg2ps1 $path
这是最终版本,基于我之前的脚本和 SimonS 提供的脚本。该脚本非常完整,所有错误都已修复,它可以正确解析所有 6 种注册表值类型:、、、、REG_SZ
和,将每行转换为一行,每个转换为一行,每行转换为一行,以及根据属性类型将每行REG_DWORD
转换为适当的行。它接受输入的路径,自动检测路径指向文件还是文件夹,如果文件扩展名为 .reg,则将转换后的命令输出到该文件的父文件夹中的文件中,并将其作为文件名;如果是文件夹,则转换该文件夹内的所有 .reg 文件,并为每个 .reg 文件输出一个文件到该文件夹,然后将所有命令放入文件夹中的一个文件中。REG_QWORD
REG_BINARY
REG_MULTI_SZ
REG_EXPAND_SZ
[HKEY_*
New-Item
[-HKEY_*
Remove-Item
"([^"=]+)"=-
Remove-ItemProperty
"([^"=]+)"=
Set-ItemProperty
${filename}_reg.ps1
${filename}_reg.ps1
_reg.ps1
allcommands.ps1
我进行了多次测试,确认它确实有效。脚本现已完成。我进行了重大改进,使用了更好的格式,大大简化了代码,使用了更好的逻辑,并进行了许多其他增强。
这确实完成了,要使用我的最终版本,请将函数复制粘贴到打开的 powershell 窗口中,然后像 reg2ps1 "full\path\to\content" 一样调用它,或者将其保存为 .ps1 文件并通过 cd $scriptdir 和 .\reg2ps1.ps1 运行它,然后输入 full\path\to\content,注意您不应该使用任何引号,否则找不到路径...
更新
我在代码中犯了一个错误,通过-Force
在使用时指定参数New-Item
,如果该项目已经存在,它将重新创建该项目,并在过程中清空该项目,这不是我想要的,现在已修复。通过删除行-Force
中的参数New-Item
,尝试创建一个已经存在的项目将生成一个错误,提示该项目已存在,并且不会重置该项目。错误消息被隐藏-ErrorAction SilentlyContinue
。如果该项目不存在,它将被创建,该项目将为空,过程将提示一条消息,提示该项目已创建,该消息被隐藏| Out-Null
。
答案2
这非常好,但是您的转换代码中存在一些错误。
- 在包含转义字符(如“cmd.exe /s /k pushd“%V””)的注册值文本中,您的转换不会将“替换为`”或类似的字符。
- 使用 -Type 属性时,需要 New-ItemProperty 而不是 Set-ItemProperty。
- 如果不先设置驱动器,PowerShell 将无法处理“HKCR:”等。
- Out-File 路径参数是 -FilePath
可能值得修复
答案3
根据Microsoft 参考-path
,第 125 行的命令语法中没有参数Out-File
,因此需要将其替换为正确的参数-FilePath
:
更改此行:
$Commands | Out-File -Path "${parent}\${filename}_reg.ps1" -encoding $encoding
到:
$Commands | Out-File -FilePath "${parent}\${filename}_reg.ps1" -encoding $encoding
此外,在发布“最终版本”之前,您可能需要使用这些示例注册表项检查您的代码:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\MyNewKey]
"Value01"=dword:00000a00
"Value02"=hex:c4,ff,cc,ff,00,00,00,00,e2,ff,bb,ff,00,00,09,00,01,00,03,00,27,00,\
55,00,2e,00,e7,03,00,00,03,00,00,00,03,00,c4,00,00,00,30,00,00,00
"Value03"="@tzres.dll,-243"
"Value04"=hex:00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
"Value05"=dword:ffffff2e
[HKEY_CURRENT_USER\SOFTWARE\MyNewKey]
"Value06"="1445855232"
[HKEY_USERS\S-1-5-18\Software\MyNewKey]
"Value07"=dword:00000000
使用这些案例来测试代码性能是一个好主意。我在转换时发现了很多错误...
答案4
https://reg2ps.azurewebsites.net/有一个输入表单,用户可以在其中输入.reg
代码并输出.ps1
代码。