Powershell卸载模块......完全

时间:2009-08-26 22:43:44

标签: .net powershell

我正在调试Powershell项目。我正在使用Import-Module从我的C#dll加载PS模块,一切正常。虽然DLL仍然被锁定且无法删除,但调用Remove-Module并未完全卸载模块。

有没有办法让PSH完全卸载模块并释放DLL,以便我可以复制它并使用Import-Module重新加载它而无需重新启动PSH控制台?

更新
因此,如果您将模块加载到单独的AppDomain中,它仍然像普通模块一样工作吗?任何人都可以提供一个例子吗?

10 个答案:

答案 0 :(得分:23)

有一种解决方法。打开另一个PowerShell实例:

PS > powershell
PS > [load DLL]
PS > [do work]
PS > exit

退出之后,您将被带回到进行此调用的PowerShell实例(假设您在内部进行了powershell调用和PowerShell实例)。您可以将任何常规参数传递给powershell,因此您可以使用-Co​​mmand或-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.

当PowerShell退出时,它将释放DLL上的锁定,允许您继续工作。

所有这些都是从PowerShell命令行界面完成的。我没有测试如果你在脚本中间抛出powershell或者在ISE中工作会发生什么。 (我怀疑它在ISE中有效。)即使if在脚本中不起作用,这在开发过程中仍然有用。

编辑:

做了一些检查。所以这似乎在脚本和ISE中都可以正常工作,但在ISE中有一个警告。在ISE中,当您在单独的PowerShell进程中时,无法读取用户的任何输入。如果您尝试,脚本或命令停止等待,但没有输入框像正常一样显示,当然,您不能直接键入ISE的输出窗口。因此,如果您需要在[do work]的中间提示输入,请在之前提示启动PowerShell的新实例,并将其作为参数传递给工作。如果您使用的是常规PowerShell命令行,则这些都不是问题。

答案 1 :(得分:17)

没有。由于PowerShell使用.NET,因此它具有相同的要求。 在不卸载AppDomain本身的情况下,无法从.NET AppDomain卸载dll。由于PowerShell UI位于相同的AppDomain中,因此无法实现。

答案 2 :(得分:8)

我在这里看到一些可行的答案,但这是我的,以防这对某人来说仍然是一个问题(这很懒,这很好)。

Enter-PSSession -localcomputername
[load dlls]
[execute script(s)]
Exit-PSSession

长话短说,为您的本地计算机创建PSSession会创建一个不同的PowerShell会话,包括所考虑的内容"已加载",当您退出时,它会为您清理。

答案 3 :(得分:5)

我相信这适用于PowerShell:在.NET世界中,卸载程序集的唯一方法是将其加载到不同的AppDomain;将程序集加载到AppDomain后,它会在AppDomain的生命周期内保持加载状态。


这是一个来自一个线程的例子,它提出了几乎相同的问题,并展示了一些创建和加载模块到新AppDomain的方法:

http://www.eggheadcafe.com/conversation.aspx?messageid=30789124&threadid=30766269

答案 4 :(得分:3)

我遇到了同样的问题,并最终将我想要加载的DLL包装在命令行exe中,然后我从脚本中调用它。通过这种方式,我完全避免在我的应用程序中加载DLL。

答案 5 :(得分:3)

在Cmdlet开发的上下文中,以及卸载DLL时遇到问题,我使用了两种方法。

首先,我在Visual Studio中开发,并设置外部程序(PowerShell)来加载我的Cmdlet。这样,我的模块在开始调试时加载,在我停止调试时卸载。

其次,在我知道我想要加载模块的那些场合,做一些工作,并确保之后卸载模块,我使用PowerShell的第二个实例。这在其他答案中已经讨论过了,下面的答案显示了如何通过在我的个人资料中使用带别名的功能来启用此工作流程。我更改了提示,因此我可以看到一个“递归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

编辑Cmdlet项目的调试设置

启动外部程序

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

命令行参数

-NoProfile -NoExit -Command "Import-Module .\MyCoolCmdlet.dll"

调试您的模块

现在从Visual Studio,使用 F5 启动调试器,你有一个新的PowerShell窗口加载了你的Cmdlet,你可以随意调试它。

使用任何PowerShell窗口中的“sdp”别名

由于Start-DebugPowerShell函数位于我们的配置文件中,并且我们为其指定了别名sdp,因此您可以随时使用它来启动PowerShell的第二个实例。

答案 6 :(得分:2)

我使用一个简单的脚本重命名目标DLL并将其作为模块加载。这里有2个黑客:

  1. 当模块从.net程序集对象加载时,我们加载了名为" dynamic_code_module_FirstPowershellModule"
  2. 所以在导入之前我们卸载这个模块并从重命名的文件
  3. 创建一个新模块

    以前的程序集在域

    中保持未使用状态 必须在每个项目重建后运行

    脚本

    df['MA3'] = df.groupby('Ticker').Adj_Close.transform(lambda group: pd.rolling_mean(group, window=3))
    
    >>> df
              Date  Ticker  Open  High  Low  Adj_Close   Volume  MA3
    0   2015-04-09  vws.co   315   316  312        312  1686800  NaN
    1   2015-04-10  vws.co   317   320  316        313  1396500  NaN
    2   2015-04-13  vws.co   318   322  315        316  1564500  313
    3   2015-04-14  vws.co   320   322  319        315  1370600  314
    4   2015-04-15  vws.co   320   322  319        316   945000  316
    5   2015-04-16  vws.co   319   320  310        308  2236100  313
    6   2015-04-17  vws.co   310   310  302        299  2711900  308
    7   2015-04-20  vws.co   303   312  303        306  1629700  304
    8   2016-03-31     mmm   167   168  166        167  1762800  NaN
    9   2016-04-01     mmm   166   168  165        168  1993700  NaN
    10  2016-04-04     mmm   167   167  166        166  2022800  167
    11  2016-04-05     mmm   165   167  165        166  1610300  167
    12  2016-04-06     mmm   165   167  165        167  2092200  166
    13  2016-04-07     mmm   166   167  165        167  2721900  167
    

答案 7 :(得分:0)

制作DLL的副本并加载该副本。 你可以重新加载DLL。

答案 8 :(得分:0)

PS模块是.net程序集,当您Import-Module时,将它们加载到PowerShell主机(应用程序)的AppDomain中。 Remove-Module只是从当前会话中删除模块。

根据msdn, http://msdn.microsoft.com/en-us/library/ms173101(v=vs.80).aspx

  

如果不卸载包含它的所有应用程序域,就无法卸载单个程序集。使用AppDomain中的Unload方法卸载应用程序域。有关更多信息,请参阅卸载应用程序域。

您可以在新的AppDomain中启动新的PowerShell主机,将模块导入主机并执行PowerShell作业。该模块与在先前主机中运行的模块一样正常。唯一的区别是它位于运行在不同AppDomain中的主机中。

答案 9 :(得分:0)

我有一些外部模块( ImportExcel ),我想像这样did not work进行更新。对于这种情况, Install-Module -Scope CurrentUser <MyExternalModuleName> (如果它位于用户模块文件夹中,则省略-Scope ...参数)。

(他们如何内部管理它-我不知道,但是您保留了当前的PS会话。)