A while ago I posted a function to export registry items to either a CSV or XML file. Recently I had a question on Twitter about importing, which I assumed meant from my exported file. The import is actually pretty easy as I'll show you, although it did require a change to the original Export-Registry function.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
The main challenge when creating registry entries is to get the type correct. In my original version I took a convulated and kludgy approach. But thanks to my fellow PowerShell MVPs I learned a better way to get the underlying registry type such as String, ExpandedString or DWord. First, it is much easier to get the registry keys without all the extra PSPath stuff.
[cc lang="PowerShell"]
Foreach ($item in $path) {
Write-Verbose "Getting $item"
$regItem=Get-Item -Path $item
#get property names
$properties= $RegItem.Property
[/cc]
I can now easily get each property value using the GetValue() method and the underlying type using GetValueKind().
[cc lang="PowerShell"]
foreach ($property in $properties) {
Write-Verbose "Exporting $property"
$value=$regItem.GetValue($property,$null,"DoNotExpandEnvironmentNames")
#get the registry value type
$regType=$regItem.GetValueKind($property)
$PropertyItem=$property
[/cc]
When calling GetValue(), I'm tell PowerShell not to expand environment strings, which is otherwise the default. This allows me to export %COMPUTERNAME% as the value as apposed to the expanded value. This is critical when it comes time to import. Here's my revised function with the comment based help omitted.
[cc lang="PowerShell"]
Function Export-Registry {
[cmdletBinding()]
Param(
[Parameter(Position=0,Mandatory=$True,
HelpMessage="Enter a registry path using the PSDrive format.",
ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[ValidateScript({(Test-Path $_) -AND ((Get-Item $_).PSProvider.Name -match "Registry")})]
[Alias("PSPath")]
[string[]]$Path,
[Parameter()]
[ValidateSet("csv","xml")]
[string]$ExportType,
[Parameter()]
[string]$ExportPath,
[switch]$NoBinary
)
Begin {
Write-Verbose -Message "$(Get-Date) Starting $($myinvocation.mycommand)"
#initialize an array to hold the results
$data=@()
} #close Begin
Process {
#go through each pipelined path
Foreach ($item in $path) {
Write-Verbose "Getting $item"
$regItem=Get-Item -Path $item
#get property names
$properties= $RegItem.Property
Write-Verbose "Retrieved $(($properties | measure-object).count) properties"
if (-not ($properties))
{
#no item properties were found so create a default entry
$value=$Null
$PropertyItem="(Default)"
$RegType="String"
#create a custom object for each entry and add it the temporary array
$data+=New-Object -TypeName PSObject -Property @{
"Path"=$item
"Name"=$propertyItem
"Value"=$value
"Type"=$regType
"Computername"=$env:computername
}
}
else
{
#enumrate each property getting itsname,value and type
foreach ($property in $properties) {
Write-Verbose "Exporting $property"
$value=$regItem.GetValue($property,$null,"DoNotExpandEnvironmentNames")
#get the registry value type
$regType=$regItem.GetValueKind($property)
$PropertyItem=$property
#create a custom object for each entry and add it the temporary array
$data+=New-Object -TypeName PSObject -Property @{
"Path"=$item
"Name"=$propertyItem
"Value"=$value
"Type"=$regType
"Computername"=$env:computername
}
} #foreach
} #else
}#close Foreach
} #close process
End {
#make sure we got something back
if ($data)
{
#filter out binary if specified
if ($NoBinary)
{
Write-Verbose "Removing binary values"
$data=$data | Where {$_.Type -ne "Binary"}
}
#export to a file both a type and path were specified
if ($ExportType -AND $ExportPath)
{
Write-Verbose "Exporting $ExportType data to $ExportPath"
Switch ($exportType) {
"csv" { $data | Export-CSV -Path $ExportPath -noTypeInformation }
"xml" { $data | Export-CLIXML -Path $ExportPath }
} #switch
} #if $exportType
elseif ( ($ExportType -AND (-not $ExportPath)) -OR ($ExportPath -AND (-not $ExportType)) )
{
Write-Warning "You forgot to specify both an export type and file."
}
else
{
#write data to the pipeline
$data
}
} #if $#data
else
{
Write-Verbose "No data found"
Write "No data found"
}
#exit the function
Write-Verbose -Message "$(Get-Date) Ending $($myinvocation.mycommand)"
} #close End
} #end Function
[/cc]
Now I can export a registry key to an XML format. CSV is ok if everything is a simple string, otherwise I strongly suggest using XML.
[cc lang="PowerShell"]
PS C:\> export-registry hkcu:\jdhit -ExportType XML -ExportPath C:\work\jdhitreg.xml
[/cc]
Now let's import. You could script this if you want but it is pretty straightforward. First, import the XML file and take a look at a few sample entries.
[cc lang="PowerShell"]
PS C:\> $data=Import-Clixml c:\work\jdhitreg.xml
PS C:\> $data[-1,-2,-3]
Value : %computername%
Name : computer
Path : hkcu:\jdhit
Type : ExpandString
Computername : SERENITY
Value : Jeff
Name : Name
Path : hkcu:\jdhit
Type : String
Computername : SERENITY
Value : {apple, banana, cherry}
Name : fruit
Path : hkcu:\jdhit
Type : MultiString
Computername : SERENITY
[/cc]
We have all the information we need to pipe these objects to New-ItemProperty, assuming the path already exists. I use -Force to overwrite any existing items.
[cc lang="PowerShell"]
$data | Foreach {
#$_
#Write the new entries, overwriting any existing.
New-ItemProperty -Path $_.Path -Name $_.Name -Value $_.Value -PropertyType $_.Type -Force
}
[/cc]
It should be that simple. You'll have to test things out and let me know.
Download Export-Registry-v2.ps1
1 thought on “Importing and Exporting Registry Items”
Comments are closed.