Invoke-Command issues when installing software on a remote server

I need to install an application on multiple remote servers in quiet mode. I created a script (Installer.ps1) as shown below using Powershell v3.0:

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

      

Then I call the script as shown below (the path to the installer folder may have spaces and the ServerReleaseManager.exe executable takes an argument):

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

      

I CommandNotFoundException

always get lower :

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.

      

I've tried other options like using - FilePath

with Invoke-Command

, but with the same error. I'm really blocked here. Could you please let me know why this error showed? How do I resolve the error? Or are there some better ways to deal with it. Thanks for your help.

+3


source to share


3 answers


This sounds like a double authentication issue. Once removed to the server, you will not be able to access the file share on the third server, because you cannot pass keberos based authentication.

You can try copying from the share to the remote server first (this should be done on the machine running the script) and then refer to the (now local) path in the scriptblock.

You can configure CredSSP , which is not a great idea for this purpose.

Basically, you need to avoid connecting to one computer and then connecting to another through that connection.



Code that implements the workaround that I am describing:

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

      

Notes

  • This has not been verified.
  • As Swonkie mentioned, you should set your parameters as required if that's what you want to achieve (not covered in my code).
  • You don't have to pass separate username and password parameters and then convert them to a credential object. Pass one parameter instead [PSCredential]

    . You can use the default that asks for eg [PSCredential] $Cred = (Get-Credential)

    . (this is also not covered in my code).
+2


source


Desired state configuration can be used to install software on target computers. I am guessing this might get around the double hop problem.

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

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



By the way, don't throw errors for missing required arguments. Let PowerShell handle this - it's much more convenient:

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

      

+3


source


Here I created a new PSsession for each server in the list and used the invoke command to target that server session. I tested it in my environment and it successfully installs my exe application using the / q switch on my remote servers.

This method, however, does not tell you whether you have successfully executed the command on the remote side, you will need to login to the server or execute a test path to the expected location of the installed files to check. In addition, PSsessions remain open until the console that runs the command is closed. If PSsession ends before the installation completes, the installation will fail.

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

      

+3


source







All Articles