I can run these commands and everything is as expected
reg load HKU\Kayla C:\Users\Kayla\ntuser.dat
New-Item -Force Registry::HKU\Kayla\Foo
However running this after causes an error
PS > reg unload HKU\Kayla
ERROR: Access is denied.
If I manually open up the Registry Editor I can unload the hive, but I would like to unload from a script if possible.
Update: after reading Matt’s answer I found it to work if you run a command
before collect
ing, example
0
[gc]::collect()
It appears the 0
acts as "Recycle Bin" and collect
is the
“permanent delete”.
reg unload. Removes a section of the registry that was loaded using the reg load operation. For examples of how to use this command, see Examples.
To load or unload registry hives, use Registry Editor. The Load Hive… and Unload Hive… commands affect only the HKEY_USERS and HKEY_LOCAL_MACHINE keys and are active only when these predefined keys are selected. When you load a hive into the registry, the hive becomes a subkey of one of these keys.
To add a registry subkey or add or change a registry value, make the appropriate changes in the registry, and then export the appropriate subkey or subkeys. Exported registry subkeys are automatically saved as .reg files. To make changes to the registry and export your changes to a .reg file, follow these steps:
Use either new-itemproperty or set-itemproperty to manipulate the registry. Due to the bug listed on the Connect site, is now not possible to make a call out to 'reg unload' without first closing the instance of Powershell (as I see permission denied).
Edit 2015-04-07: You may need to wait for pending finalizers after forcing garbage collection if you're hosting PowerShell and running in Debug mode. More below.
The problem is that New-Item
creates a handle to the registry key and leaves it open, and you've got to manually close that handle before the GC call can clean it up if it's all running in the same script. (You can see the open handle with Process Explorer's "Find -> Find Handle or DLL..." function; search for your key name in there.)
Fortunately, the result of New-Item
gives you easy access to that handle:
$result = New-Item # ...
$result.Handle.Close()
Now you can [gc]::Collect()
to clean up the handle and reg unload
.
In a custom PowerShell host running in Debug mode, because of differences in GC between Debug and Release modes, you may have to follow this with a call to [gc]::WaitForPendingFinalizers()
, but please read the literature, as this can deadlock under certain conditions. In my testing, Release mode works without waiting for pending finalizers.
Full working example for SOME_USER:
$path = "HKLM:\TEMP_hive\newkey" # Key we're going to create.
reg load HKLM\TEMP_hive C:\Users\SOME_USER\NTUSER.DAT
$result = New-Item -Path $path
$result.Handle.Close()
[gc]::Collect()
[gc]::WaitForPendingFinalizers() # Optional, and beware of deadlocks! Only seen this needed in Debug mode.
reg unload HKLM\TEMP_hive
Note that you do have to be an administrator and running elevated.
Details:
In my testing, [gc]::Collect()
is unable clean up the open handle as long as the same script is running that called New-Item
. Interestingly, that means in an interactive context like PowerShell ISE, if control returns to the prompt before the [gc]::Collect()
, it has the same effect and the handle becomes fair game for the collector without even closing it. In PowerShell ISE, run:
$path = "HKLM:\TEMP_hive\differentnewkey" # Key we're going to create.
reg load HKLM\TEMP_hive C:\Users\SOME_USER\NTUSER.DAT
New-Item -Path $path
Then run:
[gc]::Collect()
reg unload HKLM\TEMP_hive
reg unload
always succeeds in this context too.
Notice in that last example I no longer assign the return result of New-Item to a variable like $result, because if you do that, you'll still have that handle kicking around as long as $result is in the environment at your prompt, and reg unload
will fail again. Try it:
$path = "HKLM:\TEMP_hive\thirdnewkey" # Key we're going to create.
reg load HKLM\TEMP_hive C:\Users\SOME_USER\NTUSER.DAT
$result = New-Item -Path $path
Then run:
[gc]::Collect()
reg unload HKLM\TEMP_hive
Doesn't work until you call $result.Handle.Close()
.
Also, despite posts around the internet suggesting that there's a timing issue going on, throwing a sleep in there shouldn't change anything (unless you're in the custom host + Debug situation above, in which case I'd recommend waiting on finalizers) — it's all about if that handle is eligible for garbage collection. Would be extremely interested if anyone can explain at a deeper level just what's going on with that handle and the garbage collector.
It would appear that there might be a open reference to the hive you have loaded. Running the following command before the unload should clean up the references ( if any )
[gc]::collect()
More information can be found here
This uses the static method Collect from the GC class in .NET which is used for forcing the garbage collector to run and removing those unused references.
Also
This might be more of the same thing but just a different approach. Again, with a reference still present Get-ChildItem variable:
showed a reference to the hive under $
. Running other command to change the content of that variable seemed to allow the hive unload as well. More on this here. For example.
Get-ChildItem variable:
Name Value
---- -----
$ HKU\Kayla
In practice
While this might have not worked for you I tested this myself running with elevated rights.
PS C:\Windows\system32> reg load HKU\Kayla C:\temp\file.dat
The operation completed successfully.
PS C:\Windows\system32> New-Item -Force Registry::HKU\Kayla\Foo
Hive: HKU\Kayla
Name Property
---- --------
Foo
PS C:\Windows\system32> reg unload HKU\Kayla
ERROR: Access is denied.
PS C:\Windows\system32> Get-ChildItem variable:
Name Value
---- -----
$ HKU\Kayla
PS C:\Windows\system32> Get-ChildItem variable:
Name Value
---- -----
$ variable:
PS C:\Windows\system32> reg unload HKU\Kayla
The operation completed successfully.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With