Подтвердить что ты не робот

Модуль выгрузки Powershell... полностью

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

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

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

4b9b3361

Ответ 1

Существует обходное решение. Откройте еще один экземпляр 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 в середине script или если это работает в ISE. (Я подозреваю, что он работает в ISE.) Даже если if не работает внутри script, это все еще полезно во время разработки.

Edit:

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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


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

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

Ответ 5

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

Ответ 6

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

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

Во-вторых, в тех случаях, когда я знаю, что хочу загрузить модуль, выполнить некоторую работу и убедиться, что модуль выгружен впоследствии, я использую второй экземпляр PowerShell. Это обсуждалось в других ответах, и мой ответ ниже показывает, как включить этот рабочий процесс, используя функцию с псевдонимом в моем профиле. Я меняю подсказку, поэтому у меня есть визуальное напоминание о том, что я нахожусь в "рекурсивном окне PowerShell".

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

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

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

Ответ 7

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

Ответ 8

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

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

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

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

Ответ 9

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

  • Когда модуль загружается из .NET-сборки, мы получили загруженный модуль с именем "dynamic_code_module_FirstPowershellModule"
  • поэтому перед импортом мы выгружаем этот модуль и создаем новый из переименованного файла

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

script должен запускаться после каждого проекта 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