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.
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.