Как я могу использовать общие функции в удаленном сеансе Powershell?
У меня есть несколько скриптов Powershell для настройки веб-приложений IIS, очередей сообщений и т. Д.
Они используют набор библиотек разделяемых функций, которые мы создали, поэтому каждый скрипт начинается со строки
. .\common.ps1
для ссылки на общую библиотеку. Общая библиотека содержит набор функций, таких как Create-IisApplicationPool
, Create-MessageQueue
и тому подобное, которые затем вызываются из фактического сценария. Проблема этих сценариев заключается в том, что вам необходимо войти в систему с помощью удаленного рабочего стола и запустить их локально, поэтому я пишу несколько новых сценариев для развертывания кода в экземпляре Amazon EC2 и использования удаленного взаимодействия Powershell для их локального вызова.
Я не могу понять, как сделать эту общую библиотеку доступной в удаленном сеансе Powershell.
Вот простой пример:
functions.ps1
function Add-Title([string] $name) {
"Mr. $name"
}
function Say-HelloWorld([string] $name = "World") {
$computerName = $env:COMPUTERNAME
$greeting = Add-Title($name)
Write-Host "Hello, $greeting ($computerName)"
}
Example.ps1
. ./functions.ps1
$remoteUsername = "username"
$remotePassword = "password"
$remoteHostname = "172.16.0.100"
$securePassword = ConvertTo-SecureString -AsPlainText -Force $remotePassword
$cred = New-Object System.Management.Automation.PSCredential $remoteUsername, $securePassword
Say-HelloWorld("Spolsky")
Работая локально, это прекрасно работает - и говорит "Здравствуйте, мистер Спольский (DYLAN_PC)", как и ожидалось.
Теперь, если я заменю Say-HelloWorld
вызов с этим удаленным вызовом сценария:
Invoke-Command -computerName $remoteHostname -Credential $cred -ScriptBlock {
Say-HelloWorld("Spolsky")
}
Я получаю ошибку Powershell:
The term 'Say-HelloWorld' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is co
rrect and try again.
+ CategoryInfo : ObjectNotFound: (Say-HelloWorld:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Очевидно, что удаленный сеанс не может видеть функции, которые были импортированы локально.
Для простых функций этот синтаксис работает:
Invoke-Command -computerName $remoteHostname -Credential $cred -ScriptBlock ${function:Add-Title } -argumentlist "Spolsky"
но это не работает для любой функции, которая зависит от других функций.
Я пробовал разные вещи, используя PS-ExportSession и пытаясь передать -Session
аргументом для Invoke-Command, но не может найти способ захвата локальных функций и их зависимостей в модуле, который можно импортировать в удаленный сеанс. Любая помощь с благодарностью получена!
4 ответа
Это немного старая тема, но все ответы более округлые, чем эта.
Import-Module .\Common.ps1 -Force
# Now you can call common functions locally
$commonFunctions = (Get-Command .\Common.ps1).ScriptContents
Invoke-Command -Session $session -ArgumentList $commonFunctions -ScriptBlock {
param($commonFunctions)
Invoke-Expression $commonFunctions
# Now you can call common functions on the remote computer
}
Я ожидал, что вам нужно скопировать файл functions.ps1 перед точечной загрузкой. На самом деле я, вероятно, скопировал бы оба сценария в один и тот же каталог (например, через общий ресурс C$ admin в \\server\C$\foo
), а затем удаленно вызвать C:\foo\example.ps1
с помощью Invoke-Command
,
Вы говорите, что каждый сценарий начинается с . .\common.ps1
, но я не вижу этого в вашем примере скрипта. В любом случае, если вам нужно использовать функции в common.ps1, вы должны поместить его куда-нибудь, к которому удаленный компьютер сможет получить доступ.
Вы можете использовать перенаправленные диски в Powershell, как в сеансе RDP:
New-PSSession SERVER1 -Cred $creds | Enter-PSSession
. \\tsclient\c\common.ps1
Или вы можете поместить common.ps1 в сетевой ресурс:
. \\Server1\share\common.ps1
Или вы можете просто вставить содержимое файла common.ps1 в каждый скрипт.
Или вы можете поместить common.ps1 в локальную файловую систему удаленного компьютера.
Когда анализатор Powershell на удаленном компьютере видит ". \ Common.ps1", он пытается загрузить common.ps1 из текущего рабочего каталога, который, вероятно, является домашним каталогом любого пользователя, установившего удаленный сеанс PS.
У меня была точно такая же проблема. Я предполагаю, что это связано с удаленными вызовами, запущенными в контексте удаленного абонента. Мне удалось обойти эту проблему, указав полный локальный путь к целевой библиотеке в качестве переменной, а затем поставив библиотеку через точку:
function Get-ScriptDirectory
{
return Split-Path $script:MyInvocation.MyCommand.Path
}
function GetLocalFileName
{
param([string]$filename)
return [system.io.path]::Combine((Get-ScriptDirectory),$filename)
}
# dot-source the library using full local name to get round problem with remote invocation
$MYLIBRARY = GetLocalFileName "mylibrary.ps1"
. $MYLIBRARY