Skip to content

Instantly share code, notes, and snippets.

@realslacker
Last active April 3, 2024 18:54
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save realslacker/b400d7c0ccc22e93573c1a31dab4d8aa to your computer and use it in GitHub Desktop.
Save realslacker/b400d7c0ccc22e93573c1a31dab4d8aa to your computer and use it in GitHub Desktop.
Converts a .REG file into an XML document that is compatible with GPO preferences. The registry file can contain updates or deletions. The resulting XML file can be copy and pasted, or drag and dropped onto the GPO preferences registry window to import the file.
<#
.SYNOPSIS
Converts a .REG file into an XML document that is compatible with GPO
preferences.
.DESCRIPTION
Converts a .REG file into an XML document that is compatible with GPO
preferences. The registry file can contain updates or deletions. The
resulting XML file can be copy and pasted, or drag and dropped onto the
GPO preferences registry window to import the file.
.PARAMETER RegistryFile
The path to the registry file to convert. Accepts pipline input.
.PARAMETER Destination
Output path of the XML files. Defaults to the CWD.
.PARAMETER Description
The description for the containers generated.
.PARAMETER UpdateMode
The update mode the registry settings should use. Options are 'Update',
'Create', and 'Replace'.
.INPUTS
[System.IO.FileSystemInfo]
[String]
.OUTPUTS
[System.IO.FileSystemInfo]
.NOTES
This is a complete re-write of the Reg2Xml by Malcolm McCaffery. The original script is
available at http://chentiangemalc.wordpress.com.
New in this script:
- Cleaned up and simplified logic
- Support for deleting keys using native REG file settings
- Support for pipeline input
This script is released as-is, with no warranty. Use at your own risk.
.LINK
https://gist.github.com/realslacker/b400d7c0ccc22e93573c1a31dab4d8aa/raw/
#>
function Convert-RegToXml {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, Position=1, ValueFromPipeline)]
[ValidateScript({Test-Path $_})]
[string[]]
$RegistryFile,
[Parameter(Mandatory=$false, Position=2)]
[ValidateScript({Test-Path $_ -PathType Container})]
[string]
$Destination='.',
[string]
$Description="Imported $(Get-Date -Format 'yyyy-MM-dd')",
[ValidateSet('Update','Create','Replace')]
[string]
$UpdateMode='Update'
)
begin {
$ErrorActionPreference = 'Stop'
$UpdateAction = $UpdateMode.Substring(0,1)
$XmlSettings = New-Object System.Xml.XmlWriterSettings
$XmlSettings.Indent = $True
$XmlSettings.Encoding = [System.Text.Encoding]::UTF8
}
process {
foreach ( $RegItem in $RegistryFile ) {
Write-Verbose "Processing '$RegItem'..."
$RegItem = Get-Item $RegItem
if ( $RegItem.Extension -ne '.reg' ) {
throw [System.IO.FileFormatException]::new("File is not a REG file")
}
if ( Test-Path -Path ( Join-Path $Destination "$($RegItem.BaseName).xml" ) -PathType Leaf ) {
if ( ( Read-Host "The file '$($RegItem.BaseName).xml' already exists, overwrite? [y/N]" ) -match '^y' ) {
$XmlPath = Get-Item -Path ( Join-Path $Destination "$($RegItem.BaseName).xml" )
echo '' > $XmlPath
} else {
Write-Error "Please specify an output folder with -Destination or move the existing file"
}
} else {
# start the XML document
$XmlPath = New-Item -Path ( Join-Path $Destination "$($RegItem.BaseName).xml" ) -ItemType File
}
# start the XML writer
$XmlWriter = [System.Xml.XmlWriter]::Create($XmlPath, $XmlSettings)
# create the RegistrySettings node
$XmlWriter.WriteStartElement('Collection')
$XmlWriter.WriteAttributeString('clsid', '{53B533F5-224C-47e3-B01B-CA3B3F3FF4BF}')
$XmlWriter.WriteAttributeString('name', $RegPath )
$XmlWriter.WriteAttributeString('descr', $Description )
# read in the registry file
$RegContents = Get-Content $RegItem -Raw
# put multiline values on one line
$RegContents = $RegContents -replace '\\[\r\n]+\s+', ''
# split by lines
$RegContents = $RegContents -split '[\r\n]+'
# init the collection count
$RegCollectionOpen = $false
switch -Regex ($RegContents) {
# KEY
'^\[(-?)(([^\\]+)\\(.*))\]$' {
$RegPath = $Matches[2]
$RegHive = $Matches[3]
$RegKey = $Matches[4]
Write-Verbose "Hive: $RegHive"
Write-Verbose "Key: $RegKey"
if ($RegCollectionOpen) { $XmlWriter.WriteEndElement() }
$XmlWriter.WriteStartElement('Collection')
$XmlWriter.WriteAttributeString('clsid', '{53B533F5-224C-47e3-B01B-CA3B3F3FF4BF}')
$XmlWriter.WriteAttributeString('name', $RegPath )
$XmlWriter.WriteAttributeString('descr', $Description )
# are we deleting a registry key?
if ( $Matches[1] -eq '-' ) {
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Delete
}
$RegCollectionOpen = $true
}
# Delete (default)
'^@=-$' {
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Default `
-Delete
}
# Delete named value
'^"(.+)"=-$' {
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Name $Matches[1] `
-Delete
}
# REG_SZ (default)
'^@="(.*)"$' {
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Default `
-Value $Matches[1] `
-UpdateAction $UpdateAction
}
# REG_SZ
'^"(.+)"="(.*)"$' {
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Name $Matches[1] `
-Value $Matches[2] `
-UpdateAction $UpdateAction
}
# REG_BINARY
'^"(.+)"=hex:(.*)$' {
$BinaryValue = $Matches[2] -replace '[^0-9a-f]', ''
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Name $Matches[1] `
-Value $BinaryValue `
-Type REG_BINARY `
-UpdateAction $UpdateAction
}
# REG_DWORD
'^"(.+)"=dword:(.*)$' {
$DWordValue = $Matches[2].ToUpper()
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Name $Matches[1] `
-Value $DWordValue `
-Type REG_DWORD `
-UpdateAction $UpdateAction
}
# REG_QWORD
'^"(.+)"=hex\(b\):(.*)$' {
$QWordValue = $Matches[2].ToUpper().Split(',')
[array]::Reverse($QWordValue)
$QWordValue = $QWordValue -join ''
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Name $Matches[1] `
-Value $QWordValue `
-Type REG_QWORD `
-UpdateAction $UpdateAction
}
# REG_MULTI_SZ
'^"(.+)"=hex\(7\):(.*)$' {
$MulitStringValue = $Matches[2].ToUpper().Split(',')
$RegBytes = [byte[]]::New( $MulitStringValue.Count )
for( $i=0; $i -lt $MulitStringValue.Count; $i++) {
$RegBytes[$i] = [convert]::ToByte( $MulitStringValue[$i], 16 )
}
$MulitStringValue = [System.Text.Encoding]::Unicode.GetString( $RegBytes ) -replace '\0\0$','' -split '\0'
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Name $Matches[1] `
-Value $MulitStringValue `
-Type REG_MULTI_SZ `
-UpdateAction $UpdateAction
}
# REG_EXPAND_SZ
'^"(.+)"=hex\(2\):(.*)$' {
$ExpandStringValue = $Matches[2].ToUpper().Split(',')
$RegBytes = [byte[]]::New( $ExpandStringValue.Count )
for( $i=0; $i -lt $ExpandStringValue.Count; $i++) {
$RegBytes[$i] = [convert]::ToByte( $ExpandStringValue[$i], 16 )
}
$ExpandStringValue = [System.Text.Encoding]::Unicode.GetString( $RegBytes ) -replace '\0$',''
Helper-WriteRegItemXML -XmlWriter $XmlWriter `
-Hive $RegHive `
-Key $RegKey `
-Name $Matches[1] `
-Value $ExpandStringValue `
-Type REG_EXPAND_SZ `
-UpdateAction $UpdateAction
}
}
# if we have an open collection close it
if ($RegCollectionOpen) { $XmlWriter.WriteEndElement() }
# close the RegistrySettings node
$XmlWriter.WriteEndElement()
# close the XML file
$XmlWriter.Close()
Write-Verbose "Xml File: $XmlPath"
# output the resulting file handle
Get-Item -Path $XmlPath
}
}
}
function Helper-WriteRegItemXML {
param(
[Parameter(Mandatory=$true, ValueFromPipeline)]
[System.Xml.XmlWriter]
$XmlWriter,
[Parameter(Mandatory=$true)]
[ValidateSet('HKEY_CLASSES_ROOT', 'HKEY_CURRENT_USER', 'HKEY_LOCAL_MACHINE', 'HKEY_USERS', 'HKEY_CURRENT_CONFIG')]
[string]
$Hive,
[Parameter(Mandatory=$true)]
[string]
$Key,
[Parameter(ParameterSetName='Delete')]
[Parameter(ParameterSetName='DefaultKey')]
[switch]
$Default,
[Parameter(ParameterSetName='Delete')]
[switch]
$Delete,
[Parameter(ParameterSetName='Delete', Mandatory=$false)]
[Parameter(ParameterSetName='NamedKey', Mandatory=$true)]
[string]
$Name='',
[Parameter(ParameterSetName='NamedKey')]
[ValidateSet('REG_SZ', 'REG_BINARY', 'REG_DWORD', 'REG_QWORD', 'REG_MULTI_SZ', 'REG_EXPAND_SZ')]
[string]
$Type='REG_SZ',
[Parameter(ParameterSetName='DefaultKey')]
[Parameter(ParameterSetName='NamedKey')]
[string[]]
$Value='',
[Parameter(ParameterSetName='DefaultKey', Mandatory=$true)]
[Parameter(ParameterSetName='NamedKey', Mandatory=$true)]
[ValidateSet('C', 'R', 'U')]
[string]
$UpdateAction
)
# Default value
if ( $Default.IsPresent ) {
$RegName = $RegKey.Split('\\')[-1]
$RegStatus = '(Default)'
$Name = ''
}
# Named value
elseif ( -not [string]::IsNullOrEmpty( $Name ) ) {
$RegName = $Name
$RegStaus = $Name
}
# Registry key
else {
$RegName = $RegKey.Split('\\')[-1]
$RegStatus = $RegKey.Split('\\')[-1]
$Name = ''
}
$XmlWriter.WriteStartElement('Registry')
$XmlWriter.WriteAttributeString('clsid', '{9CD4B2F4-923D-47f5-A062-E897DD1DAD50}' )
$XmlWriter.WriteAttributeString('name', $RegName )
$XmlWriter.WriteAttributeString('status', $RegStatus )
$XmlWriter.WriteAttributeString('image', 7 )
$XmlWriter.WriteAttributeString('changed', (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') )
$XmlWriter.WriteAttributeString('uid', "{$(New-Guid)}" )
$XmlWriter.WriteStartElement('Properties')
$XmlWriter.WriteAttributeString('action', $( if ( $Delete.IsPresent ) { 'D' } else { $UpdateAction } ) )
$XmlWriter.WriteattributeString('displayDecimal', '0' )
$XmlWriter.WriteattributeString('default', $( if ( $Default.IsPresent ) { '1' } else { '0' } ) )
$XmlWriter.WriteAttributeString('hive', $Hive )
$XmlWriter.WriteAttributeString('key', $Key )
$XmlWriter.WriteattributeString('name', $Name )
$XmlWriter.WriteattributeString('type', $Type )
if ( $Type -eq 'REG_MULTI_SZ' ) {
$XmlWriter.WriteAttributeString('value', $Value -join ' ')
$XmlWriter.WriteStartElement('Values')
$Value | ForEach-Object {
$XmlWriter.WriteStartElement('Value')
$XmlWriter.WriteString($_)
$XmlWriter.WriteEndElement()
}
$XmlWriter.WriteEndElement()
}
else {
$XmlWriter.WriteAttributeString('value', $Value )
}
$XmlWriter.WriteEndElement()
$XmlWriter.WriteEndElement()
}
Export-ModuleMember -Function Convert-RegToXml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment