我可以运行这些命令,一切都按预期进行
reg load HKU\Kayla C:\Users\Kayla\ntuser.dat
New-Item -Force Registry::HKU\Kayla\Foo
但是在运行之后会导致错误
PS > reg unload HKU\Kayla
ERROR: Access is denied.
如果我手动打开注册表编辑器,我可以卸载配置单元,但我会 喜欢在可能的情况下从脚本中卸载。
更新:在阅读了Matt的回答之后,如果你运行一个命令,我发现它可以工作
在collect
之前,例如
0
[gc]::collect()
似乎0
充当"回收站"而collect
就是
“永久删除”。
答案 0 :(得分:3)
编辑2015-04-07:如果您正在托管PowerShell并在调试模式下运行,则可能需要在强制垃圾回收后等待挂起的终结器。更多信息如下。
问题是New-Item
创建了一个注册表项的句柄并使其保持打开状态,如果GC调用全部在同一个脚本中运行,那么你必须手动关闭该句柄才能清除它。 。 (您可以使用Process Explorer的“查找 - >查找句柄或DLL ...”功能查看打开的句柄;在那里搜索您的密钥名称。)
幸运的是,New-Item
的结果使您可以轻松访问该句柄:
$result = New-Item # ...
$result.Handle.Close()
现在您可以[gc]::Collect()
清理句柄和reg unload
。
在以调试模式运行的自定义PowerShell主机中,由于differences in GC between Debug and Release modes,您可能必须通过调用[gc]::WaitForPendingFinalizers()
来执行此操作,但请阅读the literature,因为这可能会导致死锁在一定条件下。在我的测试中,Release模式无需等待挂起的终结器即可运行。
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
请注意,您必须是管理员并且已经提升。
<强>详细信息:强>
在我的测试中,只要运行名为[gc]::Collect()
的相同脚本,New-Item
就无法清理打开的句柄。有趣的是,这意味着在像PowerShell ISE这样的交互式上下文中,如果控件返回到[gc]::Collect()
之前的提示符,它具有相同的效果,并且句柄变为收集器的公平游戏,甚至没有关闭它。在PowerShell ISE中,运行:
$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
然后运行:
[gc]::Collect()
reg unload HKLM\TEMP_hive
reg unload
也总是在这种情况下取得成功。
请注意,在最后一个示例中,我不再将New-Item的返回结果分配给变量,如$ result,因为如果你这样做,只要$ result在环境中,你仍然可以使用该句柄在您的提示下,reg unload
将再次失败。试试吧:
$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
然后运行:
[gc]::Collect()
reg unload HKLM\TEMP_hive
在致电$result.Handle.Close()
之前无效。
此外,尽管互联网上的帖子表明存在时间问题,但在那里睡一觉不应该改变任何东西(除非你在上面的自定义主机+调试情况中,在这种情况下我建议等待终结者) - 如果该句柄符合垃圾收集的条件,那就完全了。如果有人能够在更深层次上解释该句柄和垃圾收集器发生了什么,那将是非常感兴趣的。
答案 1 :(得分:1)
似乎可能存在对已加载的配置单元的开放引用。在卸载之前运行以下命令应该清理引用(如果有的话)
[gc]::collect()
可以找到更多信息here
这使用.NET中的GC类的静态方法Collect 用于强制垃圾收集器运行和删除它们 未使用的参考文献。
同时强>
这可能更像是一回事,但只是一种不同的方法。同样,仍然存在引用Get-ChildItem variable:
显示$
下的蜂巢的引用。运行其他命令来更改该变量的内容似乎也允许hive卸载。有关此问题的更多信息here。例如。
Get-ChildItem variable:
Name Value
---- -----
$ HKU\Kayla
在实践中
虽然这可能对你不起作用,但我自己运行时提升了权限。
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.
答案 2 :(得分:0)
要完全避免担心打开句柄,可以使用[Microsoft.Win32.Registry] :: SetValue,它将在设置值后关闭句柄。请参阅Microsoft documentation。