Powershell by default provides access to the registry via a PSProvider
. Running Get-PSDrive
shows this, the namespace HKCU
and HKLM
are available along with the defaults for the local file system and other locations.
As of Powershell 4.0 the registry PSProvider
can only access a registry hive that is already loaded into the currently logged on profile, it is not possible to load a hive directly from a file. It is however possible to make use of the tool reg.exe
and the registry PSProvider
together to load an external file. The blog post here explains the basics nicely.
Usage
Lets wrap up the steps from the linked blog into a couple of cmdlets, Import-RegistryHive
and Remove-RegistryHive
. As an example we will edit the NTUSER.DAT
hive from the Default
user profile in Windows 8.1, helpful if you are not able apply profile settings via Group Policy for example. Please remember running any scripts is at your own risk, make a backup first!
# load the NTUSER.DAT into HKLM\TEMP_HIVE, this can be accessed using the PSDrive TempHive
Import-RegistryHive -File 'C:\Users\Default\NTUSER.DAT' -Key 'HKLM\TEMP_HIVE' -Name TempHive
# using TempHive we make changes to turn on "boot to desktop" in the Default profile
New-Item -Path 'TempHive:\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage' -Force | Out-Null
New-ItemProperty -Path 'TempHive:\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage' -Name 'OpenAtLogon' -Value '0' -PropertyType 'DWORD' | Out-Null
# remove TempHive and unload the registry hive HKLM\TEMP_HIVE
Remove-RegistryHive -Name TempHive
Advanced Usage
This example provides a solution for unload errors where resources related to the loaded key have not been released in time. Removing the the pipe to Out-Null
for the registry edits used in the previous example should show this happening, as (on my machine) printing out the result of the registry changes delays execution enough to require a second attempt at removal.
Import-RegistryHive -File 'C:\Users\Default\NTUSER.DAT' -Key 'HKLM\TEMP_HIVE' -Name TempHive
New-Item -Path 'TempHive:\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage' -Force
New-ItemProperty -Path 'TempHive:\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage' -Name 'OpenAtLogon' -Value '0' -PropertyType 'DWORD'
# attempt Remove-RegistryHive a maximum of 3 times
$attempt = 0
while($true)
{
try
{
# when Remove-RegistryHive is successful break will stop the loop
$attempt++
Remove-RegistryHive -Name TempHive
Write-Host 'NTUSER.DAT updated successfully!'
break
}
catch
{
if ($attempt -eq 3)
{
# rethrow the exception, we gave up
throw
}
Write-Host 'Remove-RegistryHive failed, trying again...'
# wait for 100ms and trigger the garbage collector
Start-Sleep -Milliseconds 100
[gc]::Collect()
}
}
The Functions
This is the code for the two cmdlets. The download link just bellow has a Powershell module file containing these. The functions in the module have some custom exceptions and extra help text that clutters the code, so it was omitted for the example on the page here.
The module can be loaded into Powershell using the command Import-Module ImportRegistryHive
, the module file must be placed in one of the default locations Powershell defines. In most cases that will be %USERPROFILE%\Documents\WindowsPowerShell\Modules\ImportRegistryHive\ImportRegistryHive.psm1
.
Function Import-RegistryHive
{
[CmdletBinding()]
Param(
[String][Parameter(Mandatory=$true)]$File,
# check the registry key name is not an invalid format
[String][Parameter(Mandatory=$true)][ValidatePattern('^(HKLM\\|HKCU\\)[a-zA-Z0-9- _\\]+$')]$Key,
# check the PSDrive name does not include invalid characters
[String][Parameter(Mandatory=$true)][ValidatePattern('^[^;~/\\\.\:]+$')]$Name
)
# check whether the drive name is available
$TestDrive = Get-PSDrive -Name $Name -EA SilentlyContinue
if ($TestDrive -ne $null)
{
throw [Management.Automation.SessionStateException] "A drive with the name '$Name' already exists."
}
$Process = Start-Process -FilePath "$env:WINDIR\system32\reg.exe" -ArgumentList "load $Key $File" -WindowStyle Hidden -PassThru -Wait
if ($Process.ExitCode)
{
throw [Management.Automation.PSInvalidOperationException] "The registry hive '$File' failed to load. Verify the source path or target registry key."
}
try
{
# validate patten on $Name in the Params and the drive name check at the start make it very unlikely New-PSDrive will fail
New-PSDrive -Name $Name -PSProvider Registry -Root $Key -Scope Global -EA Stop | Out-Null
}
catch
{
throw [Management.Automation.PSInvalidOperationException] "A critical error creating drive '$Name' has caused the registy key '$Key' to be left loaded, this must be unloaded manually."
}
}
Function Remove-RegistryHive
{
[CmdletBinding()]
Param(
[String][Parameter(Mandatory=$true)][ValidatePattern('^[^;~/\\\.\:]+$')]$Name
)
# set -ErrorAction Stop as we never want to proceed if the drive doesnt exist
$Drive = Get-PSDrive -Name $Name -EA Stop
# $Drive.Root is the path to the registry key, save this before the drive is removed
$Key = $Drive.Root
# remove the drive, the only reason this should fail is if the reasource is busy
Remove-PSDrive $Name -EA Stop
$Process = Start-Process -FilePath "$env:WINDIR\system32\reg.exe" -ArgumentList "unload $Key" -WindowStyle Hidden -PassThru -Wait
if ($Process.ExitCode)
{
# if "reg unload" fails due to the resource being busy, the drive gets added back to keep the original state
New-PSDrive -Name $Name -PSProvider Registry -Root $Key -Scope Global -EA Stop | Out-Null
throw [Management.Automation.PSInvalidOperationException] "The registry key '$Key' could not be unloaded, the key may still be in use."
}
}
Download ImportRegistryHive.psm1
Custom Exceptions
It is unlikely a custom exception will be needed in most situations, however there is a use case when integrating an external process, or if simply making the exception more clear is helpful. This is covered when using reg.exe
in the functions above, so I took the opportunity to add some custom exceptions to the code.
The best (and only?) online resource is this post on the subject http://www.powershellmagazine.com/2011/09/14/custom-errors/, which covers pretty much everything. Also helpful are some basics from MSDN, Error Reporting Concepts, Interpreting ErrorRecord Objects and a list of error categories in ErrorCategory Enumeration.
Comments
comments powered by Disqus