Пользовательский модуль PowerShell и область действия для передачи на удаленные компьютеры
Я получаю смешанные результаты с наличием пользовательских функций в пользовательских модулях, на удаленных компьютерах, в зависимости от того, как я загружаю модуль. Деталь выглядит следующим образом:
Я написал специальный модуль, в котором есть отдельный файл функций. Структура выглядит следующим образом:
- C: \ PowerShell-модули \ ModuleName
- C: \ PowerShell-модули \ ModuleName.psd1
- C: \ PowerShell-Modules \ MyFunction.ps1 (содержит функцию MyFunction).
Чтобы полагаться на автоматическую загрузку модуля, я изменяю $env:PSModulePath, чтобы он содержал "C:\PowerShell-Modules\".
В моем скрипте (например, PassRemote.ps1) "MyFunction" доступна и работает как положено. Однако при попытке запустить это на удаленном компьютере:
Invoke-Command -ComputerName $computername -UseSSL -ScriptBlock ${function:MyFunction} -ArgumentList $arg1
... происходит сбой, сообщая, что командлет / функция не распознан.
Единственный способ передать пользовательскую функцию - это явно загрузить модуль в сценарии. Чтобы было понятно, мне нужно написать строку:
Import-Module ModuleName
внутри родительского скрипта (PassRemote.ps1). Только тогда функция может быть передана в удаленный сеанс.
Это проблема сферы?
1 ответ
Кажется, что явная загрузка модуля также загружает все содержимое функций / командлетов внутри него (то есть сам код). Таким образом, функции доступны для передачи во всей их полноте.
При автоматической загрузке модулей загружаются только имена доступных командлетов / функций (очевидно, в противном случае PS3+ потребовалось бы много времени для загрузки при запуске). Это означает, что, хотя сеанс PS "осведомлен" об автоматически загружаемых функциях, в этот момент он фактически не имеет кода для передачи в удаленный сеанс. К сожалению, использование "-ScriptBlock ${function:MyFunction}", похоже, не приводит к принудительному расширению или загрузке этой функции, чтобы она была доступна для прохождения.
Чтобы доказать приведенную выше теорию (и избежать явной загрузки модуля), мы можем запустить:
$x = Get-Command MyFunction
а потом:
Invoke-Command -ComputerName $computername -UseSSL -ScriptBlock ${function:MyFunction} -ArgumentList $arg1
Было бы неплохо, если бы был какой-то способ сделать это в строке Invoke-Command, но я думаю, что именно поэтому я испытывал описанные выше сценарии.