У меня два сервера. Серверу A необходимо связаться с сервером B и запустить определенную функцию в библиотеке функций PowerShell (просто файл .ps1), которую я создал. Вызываемая функция также вызывает другие функции во время выполнения, все из которых содержатся в том же файле .ps1. Наконец, когда сервер A вызывает функцию, которая находится на сервере B, ему также необходимо передать 5 параметров функции.
Используя несколько комбинаций New-PSSession, Enter-PSSession или просто Invoke-Command, я могу успешно вызвать функцию сервера B; однако вот где я застрял.
Я добился успеха только в том, что функция сервера B предложила мне параметры, которые она ожидает, если я перед этим выполню Import-Module на сервере A и импортирую копию файла .ps1, из которого я пытаюсь вызвать функцию. Без этого удаленная функция на сервере B не может быть найдена или распознана.
Если я не импортирую модуль, когда я вызываю функцию на сервере B, я могу заставить его выполнять простые операции, такие как эхо или запись-вывод, но функции не могут быть распознаны.
Наконец, основываясь на ситуации, в которой я могу импортировать модуль и успешно получить функцию, которая запрашивает у меня ввод, после ввода начинает выполняться базовая функция на сервере B, однако она терпит неудачу, когда вызываются подфункции внутри нее, для обновления журналов и т. д., указывая на то, что он не может их распознать. Опять же, все они содержатся в одном файле .ps1.
Вот несколько примеров кода, описывающих то, что я пытаюсь сделать:
ПРИМЕР 1
На сервере A выполняется следующее:
Invoke-Command -ScriptBlock { \\SERVERB\c$\orchestration\scripts\IvantiSyncEngine_RemotePatchRequest.ps1 }
Вот целевой файл IvantiSyncEngine_RemotePatchRequest.ps1 на сервере B, который мы вызываем в приведенном выше скрипте:
# IvantiSyncEngine_RemotePatchRequest.ps1
Write-Output "Here we go!"
И результат на сервере A такой, как ожидалось:
PS C:\> Invoke-Command -ScriptBlock { \\SERVERB\c$\orchestration\scripts\IvantiSyncEngine_RemotePatchRequest.ps1 }
Here we go!
ПРИМЕР 2
Двигаясь вперед, я расширил сценарий на сервере B, чтобы он выглядел следующим образом:
# IvantiSyncEngine_RemotePatchRequest.ps1
Write-Output "Here we go!"
Request-RemotePatch
Вызываемая функция также существует на сервере B в отдельном файле .ps1. Эта функция выглядит так:
function Request-RemotePatch {
Param (
# Define the parameters this function accepts
[Parameter(Mandatory=$true, Position=0)]
[string] $PatchHostname,
[Parameter(Mandatory=$true, Position=1)]
[string] $PatchDomain,
[Parameter(Mandatory=$true, Position=2)]
[string] $PatchRebootType,
[Parameter(Mandatory=$true, Position=3)]
[string] $RequesterHostname,
[Parameter(Mandatory=$true, Position=4)]
[string] $RequesterUsername
)
Begin{
}Process{
Write-Output "Testing"
# Empty line for spacing
Update-Log $global:RemotePatchLog "`n"
# Log to RemoteRequests log file
$MixedMessage = "Request received from $RequesterHostname\$RequesterUsername to remotely patch $PatchHostname, on domain $PatchDomain, with reboot type $PatchRebootType."
Update-Log $global:RemotePatchLog $MixedMessage
# Initialize the scan
Update-Log $global:RemotePatchLog "Scanning..."
$scan = Start-PatchScan -Name "RemoteAPI-Scan" -EndpointNames $PatchHostname -TemplateName "Security Patch Scan"
# Wait for the scan to complete and return details
$scan | Watch-PatchScan
Update-Log $global:RemotePatchLog "Scanning complete."
# Deploy against that scan
Update-Log $global:RemotePatchLog "Deploying Patches..."
$DeployTemplateName = "RemoteAPI-" + $PatchRebootType
$deploy = Start-PatchDeploy -ScanUid ($scan.Uid) -TemplateName $DeployTemplateName
# Wait for deploy to complete and return details
$deploy | Watch-PatchDeploy
Update-Log $global:RemotePatchLog "Deployment complete."
}
End{}
}
Как видите, он принимает 5 параметров. Он также вызывает другие функции в том же файле .ps1 в основном для таких вещей, как ведение журнала.
Наконец, когда я пытаюсь выполнить тот же вызов с сервера A, я получаю следующее:
PS C:\> Invoke-Command -ScriptBlock { \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_RemotePatchRequest.ps1 }
Here we go!
cmdlet Request-RemotePatch at command pipeline position 1
Supply values for the following parameters:
PatchHostname:
Так что до сих пор все работает, как ожидалось. Однако в настоящее время я не передаю параметры удаленной функции, которую хочу исправить. Но пока, чтобы проиллюстрировать, что происходит, я просто введу значение в предоставленных подсказках. Вот последняя настройка, прежде чем я нажму Enter для выполнения:
PS C:\> Invoke-Command -ScriptBlock { \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_RemotePatchRequest.ps1 }
Here we go!
cmdlet Request-RemotePatch at command pipeline position 1
Supply values for the following parameters:
PatchHostname: kam1oqapp161
PatchDomain: connex
PatchRebootType: NoReboot
RequesterHostname: kam1oqweb163
RequesterUsername: Joey
И после нажатия кнопки «Выполнить» мы получаем следующее:
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+ Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], DirectoryNotFoundException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
Request received from kam1oqweb163\Joey to remotely patch kam1oqapp161, on domain connex, with reboot type NoReboot.
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+ Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], DirectoryNotFoundException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
Scanning...
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+ Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], DirectoryNotFoundException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
Start-PatchScan : The term 'Start-PatchScan' 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
correct and try again.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:675 char:17
+ $scan = Start-PatchScan -Name "RemoteAPI-Scan" -EndpointNames $PatchHost ...
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Start-PatchScan:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Watch-PatchScan : The term 'Watch-PatchScan' 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
correct and try again.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:678 char:17
+ $scan | Watch-PatchScan
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Watch-PatchScan:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Scanning complete.
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+ Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], DirectoryNotFoundException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
Deploying Patches...
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+ Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], DirectoryNotFoundException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
Start-PatchDeploy : The term 'Start-PatchDeploy' 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 correct and try again.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:684 char:19
+ $deploy = Start-PatchDeploy -ScanUid ($scan.Uid) -TemplateName $DeployTe ...
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Start-PatchDeploy:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Watch-PatchDeploy : The term 'Watch-PatchDeploy' 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 correct and try again.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:687 char:19
+ $deploy | Watch-PatchDeploy
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Watch-PatchDeploy:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Deployment complete.
Out-File : Could not find a part of the path 'C:\Orchestration\Logs\RemotePatch.log'.
At \\kam1osapp56\c$\orchestration\scripts\IvantiSyncEngine_Functions.ps1:326 char:9
+ Out-File -filePath $TheLogFile -InputObject $TheLogPayload -Append
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], DirectoryNotFoundException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
Я остановлюсь здесь. Цитирование кода не сохраняет окраску, но здесь много красного. Ошибки связаны с двумя проблемами. (1) неспособность найти ссылки на папки и их расположение и (2) неспособность распознавать другие вызываемые функции и команды.
Вопрос 1: Почему удаленная функция, имеющая ссылки на местоположения удаленных папок, с трудом находит эти местоположения? Я вызываю только стартовую функцию с сервера A, и она запускает все остальное с сервера B. Разве все эти ссылки на местоположение не должны быть актуальными, поскольку они вызываются с сервера B? Я предполагаю, что если я изменил все удаленные ссылки с «C: ...» на «\ ServerB \ C $ ...», это исправит это, я просто не уверен, зачем это нужно?
вопрос 2 Какое решение лучше всего подходит для функций и команд, которые не распознаются? Модуль нужно импортировать и т. Д.?
Я продолжу добавлять больше, когда мы конкретизируем эти части, потому что это то, на чем я зациклен.
Обновление 18.05.2018
Хорошо, я частично решил (1) и (2) выше. Вот что я сделал.
Я преобразовал файл функций .ps1, который я использовал, в файл .psm1, создал соответствующий манифест, настроил правильную структуру папок при обращении к модулям PS и выполнил правильную установку / импорт модуля при вызове с удаленного сервера. Выполнение всего этого загружает все необходимые функции в локальное пространство на Сервере (A), удаляя любые ошибки, касающиеся нераспознанных ссылок или функций. Когда я выполняю импорт, я использую UNC-путь. Этот новый код выглядит следующим образом:
$s = New-PSSession -ComputerName 'SERVERB.DOMAINX.DOMAINY.com'
Invoke-Command -ScriptBlock {Import-Module STProtect -PassThru} -session $s
Invoke-Command -ScriptBlock {Import-Module \\SERVERB\c$\orchestration\scripts\PSModules\IvantiSyncEngine_Functions -DisableNameChecking -PassThru} -session $s
Invoke-Command -ScriptBlock ${function:Request-RemotePatch} -ArgumentList 'TARGETSERVERTOPATCH','TARGETDOMAIN','REBOOTTYPE','MYPCNAME','MYUSER' -session $s
Remove-PSSession -session $s
Exit-PSSession
Если вы посмотрите на приведенный выше код, вы также заметите, что у меня был некоторый успех с -ArgumentList для передачи переменных в функцию, которую мы вызываем удаленно. Теперь, со всем этим, когда я вызываю удаленную функцию на сервере B с сервера A, я получаю все правильные запросы, но теперь он не работает со следующим сообщением об ошибке:
Так...
Вопрос 3
Похоже, что-то не слушает, но я так и не понял, что именно. Любые идеи?