Как импортировать пользовательский модуль PowerShell в удаленный сеанс?
Я разрабатываю пользовательский модуль PowerShell, который я хотел бы использовать в контексте удаленного сеанса на другом компьютере. Следующий код (который, очевидно, не работает) объясняет, чего я пытаюсь достичь:
import-module .MyCustomModule.psm1
$session = new-pssession -computerName server01
invoke-command -session $session -scriptblock {
<# use function defined in MyCustomModule here #>
}
первый вопрос заключается в том, возможно ли вообще достичь этого сценария? Я имею в виду, что я хотел бы, чтобы мой пользовательский модуль физически присутствовал на моей машине, а не на удаленном сервере.
Я нашел этот нить, но мне не удалось это сделать - это не позволяет создать сеанс с удаленной машины обратно на локальную. Вероятно, я столкнулся с ограничениями конфигурации, упомянутыми где-то в комментариях к этому потоку... Кроме того, автор упомянул о последствиях для производительности, которые имеют решающее значение для моего решения...
Если это возможно, то как?
версия PowerShell в настоящее время не является ограничением-если решение доступно только в PS 3.0 - Я могу жить с этим.
4 ответов
было несколько замечательных комментариев к вопросу, и я потратил некоторое время на изучение различных способов подхода к проблеме.
для начала, то, что я изначально просил, невозможно. Я имею в виду, если вы идете по пути модуля, то модуль должен физически присутствовать на целевой машине, чтобы иметь возможность Import-Module
в удаленном сеансе.
чтобы абстрагировать мой вопрос дальше, я пытаюсь создать многоразовую платформу на основе PowerShell для продукта развертывания. Это будет принудительное развертывание, что означает, что мы рекомендуем людям запускать некоторые сценарии на локальной машине для развертывания на каком-то удаленном сервере. Насколько я исследовал эту область, есть два возможных пути, которые дружественны здравому смыслу.
подход, модули
процесс:
- поместите каждую логически различную часть функциональности в модуль PowerShell (
*.psm1
) - распределить модуль к удаленной машине и расширить
PSModulePath
переменная для включения нового местоположения модулей - на клиентском компьютере создайте новый сеанс на удаленном сервере и используйте
Invoke-Command -Session $s -ScriptBlock {...}
- в блоке скрипта начать с
Import-Module CustomModule
- он будет искатьCustomModule
на удаленной машине и, очевидно, найдете его
преимущества
следующие причины любить этот подход для:
- следствием традиционная роль модуля-облегчение создания многоразовых библиотек
- согласно великой книге Windows PowerShell в действии, "модули можно использовать для создания домен-специфических применений". Насколько я понимаю, это может быть достигнуто путем объединения вложенности модулей и смешивания скриптовых / двоичных модулей для отображения интуитивного интерфейса, специфичного для определенного домена. В принципе, это тот, который я ценю больше всего для цели развертывания на основе PowerShell рамки
недостатки
важно принять во внимание следующее:
- вы должны найти способ доставки пользовательских модулей на удаленную машину. Я играл с NuGet для, и я не уверен, что он хорошо подходит для этой задачи, но есть и другие варианты, например, MSI installer или plain
xcopy
из общей папки. Кроме того, механизм доставки должен поддержать подъем / downgrade и (предпочтительно) установки с несколькими экземплярами, но это больше связано с моей задачей, чем с проблемой в целом
Скрипты подход
процесс:
- поместите каждую логически различную функциональность в отдельный скрипт PowerShell (*.ps1)
- на клиентском компьютере создайте новый сеанс на удаленном сервере и используйте
Invoke-Command -Session $s -FilePath .\myscript.ps1
для загрузки функций, определенных в скрипте на пульт сеанс - использовать другой
Invoke-Command -Session $s -ScriptBlock {...}
и обратитесь к своим пользовательским функциям-они будут там в сеансе
преимущества
следующие хорошие моменты этого подхода:
- это просто - вам не нужно знать об особенностях модуля. Просто напишите простые сценарии PowerShell, и все
- вам не нужно ничего доставлять на удаленную машину - это делает решение еще проще и меньше подвержен ошибкам в обслуживании
недостатки
конечно, это не идеал:
- меньше контроля над решением: например, если вы " импортируете "набор функций в сеанс, все они" импортируются "и видны пользователю, поэтому нет" инкапсуляции " и т. д. я уверен, что многие решения могут жить с этим, поэтому не решайте, основываясь только на этом пункте
- функциональность в каждом файле должно быть автономный-любой точечный источник или импорт модуля оттуда будет искать удаленную машину, а не локальную
наконец, я должен сказать, что удаленная машина все еще должна быть готова к удалению. Вот что я имею в виду:--12-->
- политика выполнения должна быть изменена на что - то, потому что она ограничена по умолчанию:
Set-ExecutionPolicy Unrestricted
- PowerShell remoting должен быть включен:
Enable-PSRemoting
- учетная запись скрипт работает как надо быть добавлены к локальным администраторам удаленного сервера
- если вы планируете получить доступ к файловым ресурсам в удаленном сеансе, убедитесь, что вы знаете о Multi-hop аутентификации и принять надлежащие меры
- убедитесь, что ваш антивирус является вашим другом и не отправляет вас в PowerShell с АД
вот еще один подход: воссоздайте модуль в удаленном сеансе без копирования каких-либо файлов.
Я не пытался справиться с зависимостями между модулями, но это, похоже, работает нормально для простых автономных модулей. Он полагается на модуль, доступный в локальном сеансе, так как это упрощает определение экспорта, но с небольшой дополнительной работой он также будет работать с файлом модуля.
function Import-ModuleRemotely([string] $moduleName,[System.Management.Automation.Runspaces.PSSession] $session)
{
$localModule = get-module $moduleName;
if (! $localModule)
{
write-warning "No local module by that name exists";
return;
}
function Exports([string] $paramName, $dictionary)
{
if ($dictionary.Keys.Count -gt 0)
{
$keys = $dictionary.Keys -join ",";
return " -$paramName $keys"
}
}
$fns = Exports "Function" $localModule.ExportedFunctions;
$aliases = Exports "Alias" $localModule.ExportedAliases;
$cmdlets = Exports "Cmdlet" $localModule.ExportedCmdlets;
$vars = Exports "Variable" $localModule.ExportedVariables;
$exports = "Export-ModuleMember $fns $aliases $cmdlets $vars;";
$moduleString= @"
if (get-module $moduleName)
{
remove-module $moduleName;
}
New-Module -name $moduleName {
$($localModule.Definition)
$exports;
} | import-module
"@
$script = [ScriptBlock]::Create($moduleString);
invoke-command -session $session -scriptblock $script;
}
Я не считаю, что это поддерживается справа от коробки без каких-либо"хаков". Разумным шагом, вероятно, было бы поместить модуль в общедоступное место, такое как файловый сервер, и импортировать его на сервер, когда вам это нужно. Ex:
$session = new-pssession -computerName server01
invoke-command -session $session -scriptblock {
#Set executionpolicy to bypass warnings IN THIS SESSION ONLY
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
#Import module from public location
Import-Module \fileserver\folders\modulelocation...
<# use function defined in MyCustomModule here #>
}
Как насчет создания scriptblock из вашей пользовательской функции и отправки его на серверы terget с помощью Invoke-command
Import-module YourModule
$s = [scriptblock]::Create($(get-item Function:\Your-ModuleFunction).Definition)
Invoke-Command -ScriptBlock $s -Computername s1,s2,sn