Powershell 在远程服务器中安装软件时调用命令出现问题

Powershell 在远程服务器中安装软件时调用命令出现问题,powershell,parameters,powershell-3.0,powershell-remoting,Powershell,Parameters,Powershell 3.0,Powershell Remoting,我需要在安静模式下在几个远程服务器上安装一个应用程序。我使用Powershell v3.0创建了一个脚本(Installer.ps1),如下所示: param( [String] $ServerNameFilePath = $(throw "Provide the path of text file which contains the server names"), [String] $InstallerFolderPath = $(throw "Provide the Installer F

我需要在安静模式下在几个远程服务器上安装一个应用程序。我使用Powershell v3.0创建了一个脚本(Installer.ps1),如下所示:

param(
[String] $ServerNameFilePath = $(throw "Provide the path of text file which contains the server names"),
[String] $InstallerFolderPath = $(throw "Provide the Installer Folder Path. This should be a network location"),
[String] $UserName = $(throw "Provide the User Name"),
[String] $Password= $(throw "Provide the Password")
)
Function InstallApp
{
    $secpasswd = ConvertTo-SecureString $Password -AsPlainText -Force
    $mycreds = New-Object System.Management.Automation.PSCredential ($UserName, $secpasswd)

    $ScrBlock = {param($InstallerFolderPath) $ExePath = Join-Path $InstallerFolderPath "ServerReleaseManager.exe";  & $ExePath /q;}
    Invoke-Command -ComputerName (Get-Content Servers.txt) -Credential $mycreds $ScrBlock -ArgumentList $InstallerFolderPath

}

InstallApp -ServerNameFilePath $ServerNameFilePath -InstallerFolderPath $InstallerFolderPath -UserName $UserName -Password $Password
然后我像下面这样调用脚本(安装程序文件夹路径可以有空格,可执行文件ServerReleaseManager.exe接受参数):

我总是在
CommandNotFoundException
下面查看:

The term '\\TestServer01\Public\Stable Applications\Server Release Manager Update 2\2.7\ServerReleaseManager.exe' 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.
我尝试过其他选项,比如将-
FilePath
Invoke命令一起使用,但出现了相同的错误。我在这里真的被堵住了。你能告诉我为什么会出现这个错误吗?如何解决错误?或者有没有更好的方法来处理这个问题。谢谢你的帮助。

这听起来像是一个双跳身份验证问题。一旦您被远程连接到服务器,您就无法访问第三台服务器上的文件共享,因为您无法将基于kerberos的身份验证传递给它

您可以尝试从共享复制到远程服务器,首先(这必须在执行脚本的计算机上完成),然后在脚本块中引用(现在是本地)路径

你可以,这不是一个好主意

基本上,您需要避免连接到一台机器,然后通过该连接连接到另一台机器

实现我所描述的变通方法的代码:
param(
[String]$ServerNameFilePath=$(抛出“提供包含服务器名称的文本文件的路径”),
[String]$InstallerFolderPath=$(抛出“提供安装程序文件夹路径。这应该是网络位置”),
[String]$UserName=$(抛出“提供用户名”),
[String]$Password=$(抛出“提供密码”)
)
函数InstallApp
{
$secpasswd=converttosecurestring$Password-AsPlainText-Force
$mycreds=New Object System.Management.Automation.PSCredential($UserName,$secpasswd)
$ScrBlock={param($InstallerFolderPath)$ExePath=连接路径$InstallerFolderPath“ServerReleaseManager.exe”;&$ExePath/q;}
获取Content Servers.txt | ForEach项{
$remoteDest=“\\$\uc`$\some\temp\folder”
$localDest=“C:\some\temp\folder”|连接路径-ChildPath($InstallerFolderPath |分割路径-Leaf)
试一试{
复制项目-路径$InstallerFolderPath-目标$dest-强制
调用命令-ComputerName$\凭证$mycreds$ScrBlock-ArgumentList$localDest
最后{
删除项目$remoteDest-Force-ErrorAction忽略
}
}
}
InstallApp-ServerNameFilePath$ServerNameFilePath-InstallerFolderPath$InstallerFolderPath-UserName$UserName-Password$Password
笔记
  • 这是未经测试的
  • 正如Swonkie所提到的,如果这是您希望实现的目标(我的代码中没有提到),那么您应该将参数设置为强制参数
  • 您不应传递单独的纯文本用户名和密码参数,然后将它们转换为凭据对象。而应传递单个
    [PSCredential]
    参数。您可以使用默认值进行提示,如
    [PSCredential]$Cred=(获取凭据)
    (这在我的代码中也没有解决)

  • 所需的状态配置可用于在目标机器上安装软件。我认为这可以解决双跳问题

    顺便说一句-不要因为缺少必需参数而抛出错误。让PowerShell来处理这个问题-它对用户更友好:

    param(
        [parameter(Mandatory=$true)] [string] $ServerNameFilePath,
        [parameter(Mandatory=$true)] [string] $InstallerFolderPath,
        [parameter(Mandatory=$true)] [string] $UserName,
        [parameter(Mandatory=$true)] [string] $Password
    )
    

    在这里,我为列表中的每台服务器创建了一个新的PSsession,并使用invoke命令以该服务器的会话为目标。我已经在我的环境中对其进行了测试,它成功地在我的远程服务器上安装了带有a/q开关的exe应用程序

    但是,此方法不会告诉您命令是否在远程端成功运行,您必须登录到服务器或执行到所安装文件的预期位置的测试路径以进行验证。此外,PSsessions将保持打开状态,直到启动该命令的控制台关闭。如果PSsession在安装完成之前结束s、 安装将失败

    Function InstallApp {
    
        param(
            [parameter(Mandatory=$true)] [String] $ServerNameFilePath,
            [parameter(Mandatory=$true)] [String] $InstallerFilePath,
            [parameter(Mandatory=$true)] [String] $CommandArgument,
            [parameter(Mandatory=$true)] [String] $UserName,
            [parameter(Mandatory=$true)] [String] $Password
        )
    
        $secpasswd = ConvertTo-SecureString $Password -AsPlainText -Force
        $mycreds = New-Object System.Management.Automation.PSCredential ($UserName, $secpasswd)
    
        Get-Content $ServerNameFilePath | ForEach-Object {
            $remoteSession = new-PSSession $_ -Credential $mycreds
            Invoke-command -Session $remoteSession -Scriptblock {& ($args[0]) @($args[1])} -ArgumentList $InstallerFilePath,$CommandArgument 
        }
    }
    
    InstallApp -ServerNameFilePath $ServerNameFilePath -InstallerFilePath $InstallerFilePath -CommandArgument $CommandArgument -UserName $UserName -Password $Password
    

    我看到的一个问题是您有
    -ComputerName(Get Content Servers.txt)
    ,我想您希望它是
    -ComputerName(Get Content$ServerNameFilePath)
    是的..这是一个错误..但它不能解决问题,您没有显示
    -ScriptBlock
    参数…我必须检查,但可能存在位置问题。在
    $ScrBlock
    的from中使用参数名称,如
    -ScriptBlock$ScrBlock
    会有所帮助。在您的参数集中,它是位置0,但它是lo在位置1中查找。尝试使用
    -ScriptBlock
    谢谢你的建议。但我以前也尝试过。运气不好。你确定路径吗?包括服务器名称。你是否验证了文件确实位于该位置?我们的服务器中没有设置CredSSP。我不允许这样做。这就是我使用-Authentication的原因CredSSP,我得到以下错误:“WinRM客户端无法处理该请求。计算机策略不允许将用户凭据委派给目标计算机。”是否有其他方法解决此问题?没有灵丹妙药。正如我所说,您可以将文件复制到远程服务器,然后使用本地(到服务器)引用它们路径。如果您没有更改策略或配置的权限,则您的选项是有限的。Edited可能会回答一些详细信息。DSC更容易出现双跳问题,因为它始终使用远程处理,即使在推送模式下也是如此。请参阅我的回答:据我所知,它是在目标计算机上运行的服务,其中实际上(使用提供程序)对目标计算机进行更改,但它不会使用创建配置的用户的凭据。链接答案下的注释也会提到类似的内容。
    Function InstallApp {
    
        param(
            [parameter(Mandatory=$true)] [String] $ServerNameFilePath,
            [parameter(Mandatory=$true)] [String] $InstallerFilePath,
            [parameter(Mandatory=$true)] [String] $CommandArgument,
            [parameter(Mandatory=$true)] [String] $UserName,
            [parameter(Mandatory=$true)] [String] $Password
        )
    
        $secpasswd = ConvertTo-SecureString $Password -AsPlainText -Force
        $mycreds = New-Object System.Management.Automation.PSCredential ($UserName, $secpasswd)
    
        Get-Content $ServerNameFilePath | ForEach-Object {
            $remoteSession = new-PSSession $_ -Credential $mycreds
            Invoke-command -Session $remoteSession -Scriptblock {& ($args[0]) @($args[1])} -ArgumentList $InstallerFilePath,$CommandArgument 
        }
    }
    
    InstallApp -ServerNameFilePath $ServerNameFilePath -InstallerFilePath $InstallerFilePath -CommandArgument $CommandArgument -UserName $UserName -Password $Password