在远程服务器中安装软件时Invoke-Command的问题

时间:2014-10-31 15:15:12

标签: powershell parameters powershell-v3.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 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

然后我调用下面的脚本(Installer文件夹路径可以有空格,可执行文件ServerReleaseManager.exe接受参数):

.\Installer.ps1 -ServerNameFilePath Servers.txt -InstallerFolderPath "\\TestServer01\Public\Stable Applications\Server Release Manager Update 2\2.7" -UserName "Domain\User" -Password "Test123"

我总是低于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.

我尝试了其他选项,例如使用FilePathInvoke-Command但错误相同。我在这里真的被封锁了。你能告诉我为什么会出现这个错误吗?如何解决错误?或者有更好的方法来处理这个问题。谢谢你的帮助。

3 个答案:

答案 0 :(得分:3)

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

http://technet.microsoft.com/de-de/library/dn282132.aspx

http://technet.microsoft.com/de-de/library/dn282129.aspx

顺便说一下 - 不要因为缺少强制性参数而抛出错误。让PowerShell处理它 - 它更加用户友好:

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

答案 1 :(得分:3)

在这里,我为列表中的每个服务器创建了一个新的PSsession,并使用invoke命令来定位该服务器的会话。我在我的环境中对它进行了测试,并在远程服务器上使用/ q开关成功安装了我的exe应用程序。

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

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

答案 2 :(得分:2)

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

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

你可以set up CredSSP这对于这个目的来说并不是一个好主意。

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

实现解决方法的代码我描述:

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;}

    Get-Content Servers.txt | ForEach-Item {
        $remoteDest = "\\$_\c`$\some\temp\folder"
        $localDest = "C:\some\temp\folder" | Join-Path -ChildPath ($InstallerFolderPath | Split-Path -Leaf)

        try {
            Copy-Item -Path $InstallerFolderPath -Destination $dest -Force
            Invoke-Command -ComputerName $_ -Credential $mycreds $ScrBlock -ArgumentList $localDest
        finally {
            Remove-Item $remoteDest -Force -ErrorAction Ignore
        }
    }
}

InstallApp -ServerNameFilePath $ServerNameFilePath -InstallerFolderPath $InstallerFolderPath -UserName $UserName -Password $Password

注释

  1. 这是未经测试的。
  2. 如Swonkie所述,如果您希望实现的目标(我的代码中未解决),您应将参数设置为必填项。
  3. 您不应该传递单独的纯文本用户名和密码参数,然后将它们转换为凭据对象。而是传递一个[PSCredential]参数。您可以使用提示的默认值,例如[PSCredential] $Cred = (Get-Credential)。 (这在我的代码中也没有解决)。