.net Powershell卸载模块...完全
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1337961/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Powershell Unload Module... completely
提问by Eric Schoonover
I'm working on debugging a Powershell project. I'm using Import-Moduleto load the PS module from my C# dll and everything works fine. Calling Remove-Moduledoes not fully unload the module though as the DLL is still locked and can not be deleted.
我正在调试 Powershell 项目。我正在使用Import-Module从我的 C# dll 加载 PS 模块,一切正常。Remove-Module尽管 DLL 仍处于锁定状态且无法删除,但调用不会完全卸载模块。
Is there a way to get PSH to fully unload the module and release the DLL so that I can copy over it and reload it again using Import-Modulewithout restarting the PSH console?
有没有办法让 PSH 完全卸载模块并释放 DLL,以便我可以在Import-Module不重新启动 PSH 控制台的情况下复制它并重新加载它?
Update
So if you load a module into a seperate AppDomain does it still work like a normal module? Can anyone provide an example?
更新
因此,如果您将模块加载到单独的 AppDomain 中,它是否仍像普通模块一样工作?谁能提供一个例子?
回答by jpmc26
There is a workaround. Open up another instance of PowerShell:
有一个解决方法。打开另一个 PowerShell 实例:
PS > powershell
PS > [load DLL]
PS > [do work]
PS > exit
After the exit, you'll be brought back to the instance of PowerShell from which you made this call (assuming you made the powershellcall inside and instance of PowerShell). You can pass in any of the normal arguments to powershell, so you can use -Command or -File. E.g.,
退出后,您将返回到从中进行此调用的 PowerShell 实例(假设您在powershellPowerShell 的内部和实例中进行了调用)。您可以将任何普通参数传递给powershell,因此您可以使用 -Command 或 -File。例如,
PS > powershell -Command '[load DLL]; [do work]' # Executes a command and exits
PS > powershell -Command '.\myscript.ps1 param1 param2' # Executes the script and exits
PS > powershell -File .\myscript.ps1 param1 param2 # Executes a script and exits.
When PowerShell exits, it will release the lock on the DLL, allowing you to continue working.
当 PowerShell 退出时,它将释放对 DLL 的锁定,让您可以继续工作。
All of this was done from the PowerShell command line interface. I haven't tested what happens if you throw powershellin the middle of a script or if this works within ISE. (I suspect it works within ISE.) Even if if doesn't work inside a script, this is still useful during development.
所有这些都是从 PowerShell 命令行界面完成的。我还没有测试过如果你把powershell脚本放在中间或者这是否在 ISE 中工作会发生什么。(我怀疑它在 ISE 中有效。)即使在脚本中不起作用,这在开发过程中仍然很有用。
Edit:
编辑:
Did some checking. So this seems to work fine from within scripts and in ISE, but there's a caveat within ISE. From ISE, you can't read any input from the user while you're inside the separate PowerShell process. If you try, the script or commands stop to wait, but no input box is shown like normal, and of course, you can't type directly into the output window in ISE. So if you need to prompt for input in the middle of [do work], prompt beforefiring up a new instance of PowerShell, and pass it into the work as a parameter. These aren't problems at all if you're using the regular PowerShell command line.
做了一些检查。所以这在脚本和 ISE 中似乎工作正常,但在 ISE 中有一个警告。从 ISE 中,当您处于单独的 PowerShell 进程中时,您无法读取用户的任何输入。如果您尝试,脚本或命令会停止等待,但没有像正常那样显示输入框,当然,您不能直接在 ISE 的输出窗口中键入。因此,如果您需要在中间提示输入[do work],请在启动新的 PowerShell 实例之前进行提示,并将其作为参数传递到工作中。如果您使用常规 PowerShell 命令行,这些根本不是问题。
回答by Mischa
No. As PowerShell uses .NET underneath it has the same requirements. You cannot unload a dll from a .NET AppDomain without unloading the AppDomain itself. As the PowerShell UI lives in the same AppDomain this is not possible.
不可以。由于 PowerShell 在其下使用 .NET,因此它具有相同的要求。如果不卸载 AppDomain 本身,就无法从 .NET AppDomain 卸载 dll。由于 PowerShell UI 位于同一个 AppDomain 中,因此这是不可能的。
回答by Jesse MacNett
I see a few workable answers here, but here's mine, in case this is still a problem for someone (and this is pretty lazy, which is nice).
我在这里看到了一些可行的答案,但这是我的,以防万一这对某人来说仍然是一个问题(这很懒惰,很好)。
Enter-PSSession -localcomputername
[load dlls]
[execute script(s)]
Exit-PSSession
Long story short, creating a PSSession for your local computer creates a different powershell session, including what's considered "loaded", and when you exit, it cleans things up for you.
长话短说,为您的本地计算机创建一个 PSSession 会创建一个不同的 powershell 会话,包括被视为“已加载”的内容,当您退出时,它会为您清理内容。
回答by Kory Gill
In the context of Cmdlet development, and having issues with unloading your DLL, there are two approaches that I use.
在 Cmdlet 开发的上下文中,并且在卸载 DLL 时遇到问题,我使用了两种方法。
Firstly, I develop in Visual Studio, and setup an external program (PowerShell) to load my Cmdlet. This way, my module loads when I start debugging, and unloads when I stop debugging.
首先,我在 Visual Studio 中进行开发,并设置了一个外部程序 (PowerShell) 来加载我的 Cmdlet。这样,我的模块在我开始调试时加载,并在我停止调试时卸载。
Second, on those occasions where I know I want to load a module, do some work, and ensure the module is unloaded afterwards, I use a second instance of PowerShell. This has been discussed in other answers, and my answer below shows how I enable this workflow by using a function with an alias in my Profile. I change the prompt so I can have a visual reminder that I am in a "recursive PowerShell window".
其次,在我知道我想加载一个模块、做一些工作并确保之后卸载模块的情况下,我使用 PowerShell 的第二个实例。这已在其他答案中讨论过,下面我的答案显示了我如何通过在我的个人资料中使用带有别名的函数来启用此工作流程。我更改了提示,以便我可以看到我在“递归 PowerShell 窗口”中的视觉提醒。
Create a script in your profile to start PowerShell
在您的配置文件中创建脚本以启动 PowerShell
function Start-DebugPowerShell
{
PowerShell -NoProfile -NoExit -Command {
function prompt {
$newPrompt = "$pwd.Path [DEBUG]"
Write-Host -NoNewline -ForegroundColor Yellow $newPrompt
return '> '
}
}
}
Set-Alias -Name sdp -Value Start-DebugPowerShell
Edit debug settings for your Cmdlet project
编辑 Cmdlet 项目的调试设置
Start external program:
启动外部程序:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Command line arguments:
命令行参数:
-NoProfile -NoExit -Command "Import-Module .\MyCoolCmdlet.dll"
-NoProfile -NoExit -Command "Import-Module .\MyCoolCmdlet.dll"
Debug your Module
调试你的模块
Now from Visual Studio, start debugger with F5, and you have a new PowerShell window with your Cmdlet loaded, and you can debug it however you like.
现在在 Visual Studio 中,使用 启动调试器F5,您将拥有一个加载了 Cmdlet 的新 PowerShell 窗口,您可以随意调试它。
Use the 'sdp' alias from any PowerShell window
在任何 PowerShell 窗口中使用“sdp”别名
Since the Start-DebugPowerShell function is in our profile and we gave it an alias sdp, you can use this to start a second instance of PowerShell anytime you need it.
由于 Start-DebugPowerShell 函数在我们的配置文件中并且我们给了它一个别名sdp,您可以随时使用它来启动 PowerShell 的第二个实例。
回答by STW
I believe this holds true for PowerShell: in the .NET world the only way to unload an assembly is to load it into a different AppDomain; once an assembly is loaded to an AppDomainit remains loaded for the lifetime of that AppDomain.
我相信这适用于 PowerShell:在 .NET 世界中,卸载程序集的唯一方法是将其加载到不同的AppDomain; 一旦程序集加载到 ,AppDomain它就会在该 的生命周期内保持加载状态AppDomain。
Here's an example from a thread asking pretty much the same question and showing a couple ways to create and load the module into a new AppDomain:
这是一个来自线程的示例,该线程提出了几乎相同的问题,并展示了创建模块并将其加载到新 AppDomain 中的几种方法:
http://www.eggheadcafe.com/conversation.aspx?messageid=30789124&threadid=30766269
http://www.eggheadcafe.com/conversation.aspx?messageid=30789124&threadid=30766269
回答by Johann Strydom
I've had the same issues and ended up wrapping the DLL I wanted to load inside a commandline exe which I then called from the script. In that way I avoided loading the DLL inside my application at all.
我遇到了同样的问题,最终将我想加载的 DLL 包装在一个命令行 exe 中,然后我从脚本中调用了该 exe。这样我就完全避免在我的应用程序中加载 DLL。
回答by UNdedss
I use a simple script that renames target DLL and loads it as module. Here we have 2 hacks:
我使用一个简单的脚本来重命名目标 DLL 并将其作为模块加载。这里我们有 2 个 hack:
- when module is loading from .net assembly object we got loaded module with name "dynamic_code_module_FirstPowershellModule"
- so before import we unload this module and create new one from renamed file
- 当模块从 .net 程序集对象加载时,我们加载了名称为“dynamic_code_module_FirstPowershellModule”的模块
- 所以在导入之前我们卸载这个模块并从重命名的文件中创建一个新的
previous assemblies stay unused in domain
以前的程序集在域中未使用
script must be run after each project rebuild
脚本必须在每个项目重建后运行
Get-Module -Name "*FirstPowershellModule*" | Remove-Module
$ii++
$destPath = "D:\Dev\FirstPowershellModule\FirstPowershellModule\bin\Debug\FirstPowershellModule" + $ii+ ".dll"
Copy-Item D:\Dev\FirstPowershellModule\FirstPowershellModule\bin\Debug\FirstPowershellModule.dll -Destination $destPath
$ass = [System.Reflection.Assembly]::LoadFile($destPath)
import-module -Assembly $ass
回答by Sleeper Smith
Make a copy of the DLL and load that copy. You can Reload DLLs.
制作 DLL 的副本并加载该副本。您可以重新加载 DLL。
回答by terry
The PS modules are .net assemblies, when you Import-Module, you load them into the AppDomain of the PowerShell Host(the application). Remove-Modulejust removes modules from the current session.
PS 模块是 .net 程序集,当您Import-Module将它们加载到 PowerShell 主机(应用程序)的 AppDomain 中时。Remove-Module只是从当前会话中删除模块。
According to msdn, http://msdn.microsoft.com/en-us/library/ms173101(v=vs.80).aspx
根据 msdn,http://msdn.microsoft.com/en-us/library/ms173101(v=vs.80) .aspx
There is no way to unload an individual assembly without unloading all of the application domains that contain it. Use the Unload method from AppDomain to unload the application domains. For more information, see Unloading an Application Domain.
如果不卸载包含它的所有应用程序域,就无法卸载单个程序集。使用 AppDomain 中的 Unload 方法卸载应用程序域。有关更多信息,请参阅卸载应用程序域。
You could start a new PowerShell host in a new AppDomain, import your module to the host and do the PowerShell job. The module is as normal as it was running in your previous host. The only difference is that it is in a host running in a different AppDomain.
您可以在新的 AppDomain 中启动一个新的 PowerShell 主机,将您的模块导入主机并执行 PowerShell 作业。该模块与在您之前的主机中运行时一样正常。唯一的区别是它在运行在不同 AppDomain 中的主机中。
回答by Andreas Dietrich
I had some external module (ImportExcel) I wanted to update like this and it did not work. For this situation Install-Module -Scope CurrentUser <MyExternalModuleName>(in case it is in your users module folder, otherwise omit the -Scope ...param) worked.
我有一些外部模块 ( ImportExcel) 我想像这样更新但它不起作用。对于这种情况Install-Module -Scope CurrentUser <MyExternalModuleName>(如果它在您的用户模块文件夹中,否则省略-Scope ...参数)有效。
(How they managed it internally - I don't know, but you keep your current PS session.)
(他们如何在内部管理它 - 我不知道,但您保留当前的 PS 会话。)

