调用函数时远程 powershell 无法识别的命令

调用函数时远程 powershell 无法识别的命令

我有两台服务器。服务器 A 需要联系服务器 B 并使用我创建的 powershell 函数库(只是一个 .ps1 文件)运行特定函数。被调用的函数在执行过程中还会调用其他函数,所有这些函数都包含在同一个 .ps1 文件中。最后,当服务器 A 调用驻留在服务器 B 上的函数时,他还需要向该函数传递 5 个参数。

使用 New-PSSession、Enter-PSSession 或仅 Invoke-Command 的几种组合,我能够成功调用服务器 B 函数;然而,我遇到了困难。

  • 如果我事先在服务器 A 上执行 Import-Module 并导入我试图从中调用该函数的 .ps1 文件的副本,我才能成功让服务器 B 函数提示我输入它期望的参数。否则,无法找到或识别服务器 B 上的远程函数。

  • 如果我不导入模块,当我在服务器上调用该函数时,BI 可以让它执行简单的操作,例如 echo 或 Write-Output,但无法识别函数。

  • 最后,基于我可以导入模块并成功让函数提示我输入的情况,输入后,服务器 B 上的基本函数开始执行,但是当调用其中的子函数、更新日志等时,它会失败,表明它无法识别它们。同样,它们都包含在同一个 .ps1 文件中。

以下是一些代码示例,概述了我正在尝试做的事情:

示例 1

以下命令在服务器A上运行:

Invoke-Command -ScriptBlock { \\SERVERB\c$\orchestration\scripts\IvantiSyncEngine_RemotePatchRequest.ps1 }

以下是我们在上面的脚本中调用的服务器 B 上的目标 IvantiSyncEngine_RemotePatchRequest.ps1 文件:

# 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

我就到此为止。代码引用不会保留颜色,但这里有很多红色。错误主要围绕 2 个问题。(1) 无法找到文件夹引用和位置,以及 (2) 无法识别正在调用的其他函数和命令。

问题 1: 为什么引用远程文件夹位置的远程函数很难找到这些位置?我只从服务器 A 调用启动函数,它从服务器 B 启动所有其他函数。所有这些位置引用难道不应该相关吗,因为它们是从服务器 B 调用的?我假设如果我将所有远程引用从“C:...”更改为“\ServerB\C$...”,它就会解决问题,我只是不确定为什么有必要这样做?

问题2 对于无法识别的函数和命令,最佳实践解决方案是什么?需要导入模块等吗?

当我们充实这些部分时,我会继续添加更多内容,因为这些都是我所关注的内容。

更新日期:2018 年 5 月 18 日

好吧,我已经部分解决了上面的 (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 将变量传递给我们远程调用的函数取得了一些成功。现在,当我从服务器 A 调用服务器 B 上的远程函数时,我收到了所有正确的提示,但现在失败了,并显示以下错误消息:

在此处输入图片描述

所以...

问题 3

似乎有些东西没有在听,但我还没弄清楚到底是什么。有什么想法吗?

相关内容