PowerShell: модули, их расположение и перезагрузка
У меня есть довольно простой сценарий PS, который ссылается на кучу самостоятельно написанных модулей (psm1). Когда я запускаю свой сценарий из PowerShell ISE, я часто вытаскиваю свои волосы, потому что из-за того, что последняя версия моего модуля не выполняется (а какая-то устаревшая, где-то хранится в памяти).
У меня есть google-d и google-d, и я прочитал и попробовал, и теперь пришло время, когда я действительно хотел бы понять, что происходит, вместо того, чтобы постоянно работать над этими проблемами.
Пример кода:
(скрипт будет настраивать ПК, которые будут работать на наших машинах, настраивать общие ресурсы, создавать локальных пользователей, настраивать сетевые адаптеры и тому подобное)
Я начинаю с добавления расположения моих модулей в путь к модулю следующим образом:
# Make sure .\Modules is part of the PSModulePath environment variable
$currentPSModulePath = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
If (-Not ($currentPSModulePath -Like '*.\Modules*'))
{
[Environment]::SetEnvironmentVariable("PSModulePath", $currentPSModulePath + ";.\Modules", "Machine")
}
Write-Host ("Environment variable for PSModulePath = {0}" -f [Environment]::GetEnvironmentVariable("PSModulePath", "Machine"))
Затем я загружаю необходимые модули:
### Import Modules
Import-Module -DisableNameChecking ConfigureSystemPC
Import-Module -DisableNameChecking ConfigureChipPC
Import-Module -DisableNameChecking ConfigureEngravePC
Import-Module -DisableNameChecking ConfigureCInkPC
Import-Module -DisableNameChecking ConfigureIPPC
Import-Module -DisableNameChecking ConfigureNPPC
И, наконец, я спрашиваю пользователя, какой ПК должен быть настроен:
### Start configuring new PC ###
Write-Host "`nChoose the PC type form the options below:`n"
Write-Host "1. System PC"
Write-Host "2. Chip PC"
Write-Host "3. Engrave PC"
Write-Host "4. CInkjet PC"
Write-Host "5. IP PC"
Write-Host "6. NP PC"
Write-Host "7. Output PC"
$pcType = Read-Host "Please enter the PC type and press [enter]"
Write-Host ("You choose option: {0}" -f $pcType)
switch ($pcType)
{
1 { Configure-SystemPC }
2 { Configure-ChipPC }
3 { Configure-EngravePC }
4 { Configure-CInkPC }
5 { Configure-IPPC }
6 { Configure-NPPC }
7 { Configure-OutputPC }
}
Проблема возникает, когда я что-то меняю в своем Configure-модуле. Когда я просто добавляю (например) Write-Host "bla bla"
, нажмите кнопку "Сохранить" и снова отладьте мой основной скрипт (скрипт, показанный выше), PowerShell запустит старую версию модуля.
Если я не перезагружаю модуль одним из следующих способов:
rmo Configure-EngravePC
с последующимipmo Configure-EngravePC
ipmo Configure-EngravePC -Force
точно такая же "старая" версия моего модуля будет выполнена.
Кто подскажет, как с этим нормально бороться? И почему, почему, мне даже нужно перезагрузить модули, когда я запускаю свой скрипт через отладчик? Зачем ему "хранить" модули, которые запускались в другом сеансе?? Я делаю что-то неправильно?
Большое спасибо заранее, я надеюсь, что кто-то может уточнить это, я часто застреваю способ..
Я очень предпочитаю ответ с правильным объяснением (или ссылкой на хорошую документацию по этой теме)
1 ответ
Вам нужно перезапустить ISE, поскольку он поддерживает единую консоль AFAIK.
Теперь, чтобы сделать это без перезапуска, вам нужно будет либо создать новое пространство выполнения ISE (Файл> Новая вкладка PowerShell), либо отказаться от ISE (рекомендуется, так как оно достаточно), и использовать что-то обычное, такое как Cmder, и вводить ISE только для расширенной отладки или реализовать некоторую форму автозагрузки.
Плохое решение было бы заменить prompt
функция, когда вы вводите ISE (или добавляете это в свой профиль):
rename-item Function:prompt Function:old_prompt -ErrorAction ignore
function global:prompt() {
import-module -force Configure-EngravePC
Function:old_prompt
}
Это будет работать нормально, за исключением первого запроса после изменения, поскольку функция приглашения еще не выполнена. Вы можете оптимизировать это, чтобы перезагрузить модуль, только если файл был недавно изменен (как за последние 10 минут).
Поскольку это первое приглашение может быть проблематичным, существуют способы его автоматизации:). Создайте скрипт Autohotkey, который отслеживает изменения модуля и отправляет его на консоль, как только обнаруживает изменения. Если вы это сделаете, тогда даже не нужно будет быстрых изменений, как вы можете Send ipmo -force..
с самим AutoHotkey. Я ROFLMAOd, когда я написал это, но это эпично и будет отлично работать, если честно, если скрипт AHK будет выполнен правильно.
Я не уверен, существует ли какой-либо другой способ автоматической перезагрузки модуля при изменении в активном сеансе, если только вы не используете некоторые странные вещи, такие как создание прокси-серверов PowerShell для всех командлетов, которые в основном будут выполнять те же функции, что и функция приглашения, заранее. Но...
РЕДАКТИРОВАТЬ
Я нашел эту штуку, которая частично связана, но я все еще думаю, что решение AHK - путь
/questions/24471677/mozhno-li-sbrosit-prostranstvo-vyipolneniya-v-powershell-ise/24471691#24471691
EDIT2
И вот сценарий Ahk, который выполняет сложную часть (я не писал проверку изменений файла, это тривиально):
;Find window
SetTitleMatchMode, 2
ise := WinExist("PowerShell ISE")
WinGetPos, x,y,w,h
;Click somewhere inside console to select it
x := x + 20
y := h - 100 ;you may need to tweak this number depending on windows theme etc...
WinActivate
CoordMode, Mouse ,Screen
Click %x%, %y%
SendInput {ESC}import-module -force Configure-EngravePC{ENTER}
Сценарий, вероятно, может быть намного лучше и точнее, но мой AHKfoo сегодня плохой...