Модуль разгрузки Powershell ... полностью - PullRequest
33 голосов
/ 27 августа 2009

Я работаю над отладкой проекта Powershell. Я использую Import-Module для загрузки модуля PS из моей библиотеки C # и все работает нормально. Вызов Remove-Module не полностью выгружает модуль, хотя DLL все еще заблокирована и не может быть удалена.

Есть ли способ заставить PSH полностью выгрузить модуль и освободить DLL, чтобы я мог скопировать его и перезагрузить снова, используя Import-Module без перезапуска консоли PSH?

Обновление
Итак, если вы загружаете модуль в отдельный AppDomain, он все еще работает как обычный модуль? Кто-нибудь может привести пример?

Ответы [ 10 ]

24 голосов
/ 10 октября 2012

Есть обходной путь. Откройте еще один экземпляр 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.) Даже если не работает внутри скрипта, это все еще полезно во время разработки.

Edit:

Сделал некоторую проверку. Так что это, кажется, работает хорошо из сценариев и в ISE, но в ISE есть предостережение. Из ISE вы не можете читать какие-либо входные данные от пользователя, пока находитесь внутри отдельного процесса PowerShell. Если вы попытаетесь, скрипт или команды перестанут ждать, но никакое поле ввода не будет отображаться, как обычно, и, конечно, вы не сможете ввести текст непосредственно в окно вывода в ISE. Поэтому, если вам нужно запросить ввод в середине [do work], запросите до запуска нового экземпляра PowerShell и передайте его в работу в качестве параметра. Это не проблема, если вы используете обычную командную строку PowerShell.

17 голосов
/ 27 августа 2009

Нет. Поскольку PowerShell использует .NET, к нему предъявляются те же требования. Вы не можете выгрузить dll из .NET AppDomain, не выгружая сам AppDomain. Поскольку пользовательский интерфейс PowerShell находится в одном домене приложений, это невозможно.

8 голосов
/ 09 декабря 2015

Я вижу несколько действенных ответов здесь, но вот мой, на случай, если это все еще проблема для кого-то (и это довольно лениво, что приятно).

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

Короче говоря, создание сеанса PSSession для вашего локального компьютера создает другой сеанс PowerShell, в том числе то, что считается "загруженным", и когда вы выходите из него, он все проясняет.

6 голосов
/ 27 августа 2009

Я считаю, что это верно для PowerShell: в мире .NET единственный способ выгрузить сборку - это загрузить ее в другой AppDomain; как только сборка загружается в AppDomain, она остается загруженной в течение всего срока действия AppDomain.


Вот пример из потока, задающего почти тот же вопрос и показывающий несколько способов создания и загрузки модуля в новый домен приложений:

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

3 голосов
/ 11 марта 2016

В контексте разработки Cmdlet и проблем с выгрузкой вашей DLL, я использую два подхода.

Во-первых, я разрабатываю в Visual Studio и настраиваю внешнюю программу (PowerShell) для загрузки моего командлета. Таким образом, мой модуль загружается, когда я начинаю отладку, и выгружается, когда я прекращаю отладку.

Во-вторых, в тех случаях, когда я знаю, что хочу загрузить модуль, выполнить некоторую работу и убедиться, что модуль выгружен впоследствии, я использую второй экземпляр 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

Редактирование настроек отладки для вашего проекта командлета

Запустить внешнюю программу :

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

Аргументы командной строки :

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

Отладка вашего модуля

Теперь из Visual Studio запустите отладчик с помощью F5 , и у вас появится новое окно PowerShell с загруженным командлетом, и вы сможете отлаживать его как угодно.

Используйте псевдоним 'sdp' из любого окна PowerShell

Поскольку функция Start-DebugPowerShell находится в нашем профиле, и мы дали ей псевдоним sdp, вы можете использовать ее для запуска второго экземпляра PowerShell в любое время, когда вам это нужно.

3 голосов
/ 25 января 2011

У меня были те же проблемы, и в итоге я обернул библиотеку DLL, которую хотел загрузить, в исполняемый файл командной строки, который я затем вызвал из скрипта. Таким образом я вообще избежал загрузки DLL внутри моего приложения.

2 голосов
/ 17 мая 2016

Я использую простой скрипт, который переименовывает целевую DLL и загружает ее как модуль. Здесь у нас есть 2 хака:

  1. при загрузке модуля из объекта сборки .net мы получили загруженный модуль с именем «dynamic_code_module_FirstPowershellModule»
  2. поэтому перед импортом мы выгружаем этот модуль и создаем новый из переименованного файла

предыдущие сборки остаются неиспользованными в домене

скрипт должен запускаться после каждой перестройки проекта

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
0 голосов
/ 03 сентября 2018

У меня был какой-то внешний модуль ( ImportExcel ). Я хотел обновить таким образом, и он не работал . Для этой ситуации сработало Install-Module -Scope CurrentUser <MyExternalModuleName> (если оно находится в папке вашего пользовательского модуля, в противном случае пропустите параметр -Scope ...).

(Как им это удалось внутренне - я не знаю, но вы продолжаете свой текущий сеанс PS.)

0 голосов
/ 07 мая 2013

Модули PS являются сборками .net, когда вы Import-Module загружаете их в домен приложений хоста PowerShell (приложения). Remove-Module просто удаляет модули из текущего сеанса.

Согласно МСДН, http://msdn.microsoft.com/en-us/library/ms173101(v=vs.80).aspx

Невозможно выгрузить отдельную сборку без выгрузки всех доменов приложений, которые ее содержат. Используйте метод Unload из AppDomain, чтобы выгрузить домены приложения. Для получения дополнительной информации см. Выгрузка домена приложения.

Вы можете запустить новый хост PowerShell в новом домене приложений, импортировать свой модуль на хост и выполнить работу PowerShell. Модуль работает так же нормально, как и на вашем предыдущем хосте. Единственное отличие состоит в том, что он находится на хосте, работающем в другом домене приложений.

0 голосов
/ 29 января 2013

Сделайте копию DLL и загрузите эту копию. Вы можете перезагружать DLL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...