I am a tinkerer who does many registry hacks and I hate having to click many .reg
files one by one; how do I convert .reg
files to PowerShell Set-ItemProperty
commands automatically?
I found a site that does so: Registry to PowerShell Converter. However the output isn't in the format I wanted; I want it to have the exact same syntax as below using
Set-ItemProperty
/Remove-Item
/New-Item
and nothing else: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
The command to produce intended result should be:
"Set-ItemProperty -Path " + $path + "-Name " + $name + "-Value " + $value
I have created an ASCII table with information found here and uploaded here, managing this [output]:
$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"
Currently, I have managed this, which is incomplete, but the idea is to loop through file by index
, assigning values to variables via regex match, changing type and hivename to ones used in 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}
}
There are six registry value types [REG_SZ
, REG_BINARY
, REG_DWORD
, REG_QWORD
, REG_MULTI_SZ
, REG_EXPAND_SZ
] and I have seen only one DWORD
value type in .reg
files, although I managed to make a registry key containing all types:
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"
How are registry types determined within a .reg
, as the intended end-result is a text file/string array/PowerShell script that contains the converted commands?
In a
.reg
, I know values for typeREG_DWORD
is written asdword
,REG_SZ
as plain text enclosed in quotes,REG_QWORD
asqword
(shown here), and have already mapped registry types to their corresponding PowerShell properties:Type Written REG_SZ
String
REG_EXPAND_SZ
ExpandString
REG_MULTI_SZ
MultiString
REG_BINARY
Binary
REG_DWORD
DWord
REG_QWORD
QWord
With the relations inferred from above:
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"} }
How can I detect and decode the registry hex babbles and are there other ways to write REG_EXPAND_SZ
, REG_MULTI_SZ
, and REG_BINARY
types in a .reg
(i.e. as ExpandString
, MultiString
and Binary
respectively)?
Script to parse registry expandable string values to plain text:
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
to parseREG_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
to parseREG_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
to parseREG_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 }
The script is almost complete, having already created Remove-Item
, New-Item
, and Remove-ItemProperty
switch conditions; now, the final piece of the puzzle is to write a regex that matches the values. When this is done, I will post it as an answer here.
Pseudo-code
if $line match [ and ]->$line match [-HKEY -> Remove-Item else $registry[$i+1] eq ""->New-Item elseif $line match "=-" -> Remove-ItemProperty
I created an ASCII hashtable to use as a dictionary:
$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) }
To look for a character at a given codepoint:
# Change: $asciihex.'00' # to: $asciihex.'ff'
To look for a character at any codepoint:
# Don't use $asciihex to print it $asciihex.$codepoint
To grep
values from lines, use -replace $name+$type
to get the value.