我正在调试一个 Powershell 项目。我使用 Import-Module
从我的 C# dll 中加载 PS 模块,一切正常。但是调用Remove-Module
并不能完全卸载模块,因为 DLL 仍然被锁定,无法删除。
有没有办法让 PSH 完全卸载模块,释放 DLL,以便我可以复制它并再次使用Import-Module
重新加载它,而不必重新启动 PSH 控制台?
更新:
如果将模块加载到单独的 AppDomain 中,它是否仍像普通模块一样工作?有人能提供示例吗?
我正在调试一个 Powershell 项目。我使用 Import-Module
从我的 C# dll 中加载 PS 模块,一切正常。但是调用Remove-Module
并不能完全卸载模块,因为 DLL 仍然被锁定,无法删除。
有没有办法让 PSH 完全卸载模块,释放 DLL,以便我可以复制它并再次使用Import-Module
重新加载它,而不必重新启动 PSH 控制台?
更新:
如果将模块加载到单独的 AppDomain 中,它是否仍像普通模块一样工作?有人能提供示例吗?
有一个解决方法。打开另一个PowerShell实例:
PS > powershell
PS > [load DLL]
PS > [do work]
PS > exit
退出后,您将返回到调用此命令的 PowerShell 实例(假设您在 PowerShell 实例内部调用了 powershell
命令)。您可以传递任何正常的参数给 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.
当PowerShell退出时,它将释放对DLL的锁定,允许您继续工作。所有这些都是从PowerShell命令行界面完成的。我没有测试如果在脚本中间抛出powershell
会发生什么或者这是否适用于ISE。(我认为在ISE中可以使用。)即使在脚本内部不起作用,这在开发过程中仍然很有用。[执行工作]
之间提示输入,请在启动新的PowerShell实例之前提示,并将其作为参数传递到工作中。如果您正在使用常规的PowerShell命令行,则这些问题根本就不存在。不可以。由于PowerShell在底层使用.NET,因此具有相同的要求。如果没有卸载应用程序域,就无法从.NET AppDomain中卸载dll。由于PowerShell UI位于同一应用程序域中,因此这是不可能的。
我在这里看到了一些可行的答案,但这是我的答案,以防这对某些人仍然是个问题(而且这非常简单,很好)。
Enter-PSSession -localcomputername
[load dlls]
[execute script(s)]
Exit-PSSession
简而言之,为本地计算机创建PSSession会创建一个不同的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实例。
AppDomain
中;一旦程序集加载到AppDomain
中,它将保持加载状态,直到该AppDomain
的生命周期结束。
我曾经遇到过同样的问题,最终我将想要加载的DLL包装在一个命令行exe文件中,并从脚本中调用它。这样,我完全避免了在我的应用程序中加载DLL。
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
复制 DLL 并加载该副本。您可以重新加载 DLL。
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的主机中。
我有一个外部模块(ImportExcel),我想像这样更新它,但是没有成功。对于这种情况,Install-Module -Scope CurrentUser <MyExternalModuleName>
(如果它在您的用户模块文件夹中,则省略-Scope ...
参数)可以解决问题。
(他们如何在内部管理它-我不知道,但您可以保持当前的PS会话。)