Getting MSI exit code when installing remotely using PowerShell - powershell

I use the following example to install some software on a remote computer
I would like to get the exit code back from the MSI so I can determine if successful or if not what the error was
I assumed $result would contain the information I need but I am obviously missing something
Ideas please?
$Result = Invoke-Command -computername MYREMOTEPC -ScriptBlock { Start-Process "msiexec" -ArgumentList "/i C:\tmp\MYSOFTWARE.msi /quiet /norestart" -Wait -Passthru }

Enclose the Start-Process -Passthru command in (...).ExitCode:
$Result = Invoke-Command -computername MYREMOTEPC -ScriptBlock {
(
Start-Process "msiexec" -ArgumentList "/i C:\tmp\MYSOFTWARE.msi /quiet /norestart" -Wait -PassThru
).ExitCode
}
-PassThru instructs Start-Process to output a System.Diagnostics.Process instance representing the launched process, and given that -Wait is also used, its .ExitCode property can be accessed right away.

Related

Install MSI on remote computer using Powershell

I am trying to write a Powershell script which will deploy software on a collection of WS2016 servers. I am a local administrator on all these servers. Here's what I have so far:
$Cred = Get-Credential
$Computer = 'myserver.contoso.com'
$SplunkMSI = '\\mylocalbox\C$\Splunk.msi'
$InstallDir = 'C:\Apps\Splunk\'
$sb = {
param($installer, $dir)
Start-Process -FilePath 'c:\windows\system32\msiexec.exe' -ArgumentList "$installer INSTALLDIR=$dir AGREETOLICENSE=Yes /qn /norestart /L*v C:\temp\splunkInstall.log" -Wait -NoNewWindow
}
Write-Host "Deploying Splunk to host $Computer"
Invoke-Command -Computer $Computer -Credential $Cred -ScriptBlock $sb -ArgumentList $SplunkMSI, $InstallDir -ErrorAction Stop
When I run this script, I get prompted for credentials, and then I see the output of the Write-Host, but then... nothing. I have to manually terminate the script.
I logged onto the remote host, but see no evidence that the MSI was executed or failed to execute.
Anyone see a smoking gun?
ya, it looks like it's looking for $installer and $dir in the script block but they're not specified

Using Invoke-Command to run Start-Process in an elevated session

As a precursor to running an installation file on several remote servers, I need to update the Powershell setting MaxMemoryPerShellMB. This requires running a PS session as Administrator on the remote server. I have been trying to run Invoke-Command which then runs a ScriptBlock consisting of a Start-Process command which includes the -Verb RunAs parameter. Nothing seems to work, however.
I have tried with various quoting schemes, single, double, triple, but nothing seems to work.
I've tried running the Start-Process from an Enter-PSSession, with the same results.
Following is the code I'm testing now:
$creds = Get-Credential -Username 'DOMAIN\userID' -Message "Enter Username and Password to access the remote servers."
$ScriptBlock = {
Start-Process -FilePath Powershell.exe -ArgumentList """Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 1024""" -Verb RunAs -Wait
}
Invoke-Command -ComputerName testsvr01 -Credential $creds -ScriptBlock $ScriptBlock
I should be able to RDP to the remote server and run Get-Item WSMan:\localhost\Shell and have it show the updated value, but the value isn't changed.
When running the code it pauses for a second when the Invoke-Command runs, but other than that, there is no feedback in Powershell.
On the remote server I see the following two Kerberos errors in the System Event log.
0x19 KDC_ERR_PREAUTH_REQUIRED,
0xd KDC_ERR_BADOPTION
Any help is greatly appreciated.
> powershell.exe -?
...
EXAMPLES
...
PowerShell -Command "& {Get-EventLog -LogName security}"
-Command
...
To write a string that runs a Windows PowerShell command, use the format:
"& {<command>}"
where the quotation marks indicate a string and the invoke operator (&)
causes the command to be executed.
So you could try to call Set-Item in the following way:
$ScriptBlock = {
Start-Process -FilePath Powershell.exe -ArgumentList "-Command"," &{ Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 1024 }" -Verb RunAs -Wait -PassThru
}
$process = Invoke-Command -ComputerName testsvr01 -Credential $creds -ScriptBlock $ScriptBlock
$process.ExitCode
I'm also returning a process object via -PassThru on which you might check the `ExitCode``
Hope that helps

Can't install chrome remotely through powershell script even when no error is returned

I am trying to install google chrome on a remote server but when I run my script, no error is returned and yet the MSI does not install the software automatically. This script can work locally but not remotely.
Here is the script:
$msi = "MSI path"
Invoke-Command -ComputerName RemoteServer -ScriptBlock {param($msi) Start-Process msiexec.exe -Wait -ArgumentList "/I (MSI Path) /qn /passive"} -ArgumentList $msi
Any help or feedback is appreciated.
I'm not sure, but I think your problem is that you're using the $msi as local and as remote variable. Tow options:
For readonly variables you use the "Using" keyword
See about_remote_variables about details. If you only need to read the value from a variable you can the following:
$msi = "MSI path"
Invoke-Command -ComputerName RemoteServer -ScriptBlock { Start-Process msiexec.exe -Wait -ArgumentList "/I $Using:msi /qn /passive"}
Here you don't need the ArgumentList-parameter of Invoke-Command.
Add a _remote suffix to remote variables
This is only a style I'm using in my scripts to distinguish about local and remote variables.
$msi = "MSI path"
Invoke-Command -ComputerName RemoteServer -ScriptBlock {param($msi_remote) Start-Process msiexec.exe -Wait -ArgumentList "/I $msi_remote /qn /passive"} -ArgumentList $msi
Hope that helps.
Couldnt get my script to work as it is a permission problem on the remote server. It has since been resolved.

Installing Software Using PowerShell Invoke Command

$cs = New-PSSession -ComputerName MACHINE -Credential DOMAIN\admin
Copy-Item -Path C:\Scripts\smart -Destination C:\smart -ToSession $cs
msiexec /i "C:\Smart\SMART.msi" NB_PROD_KEY=NC-2ADA2-F9RKE-AKAIA-BBB ACTIVATE_LICENSE=1 INSTALL_INK="" LAT_CONTENT="" PRINT_CAPTURE="" INSTALL_DOCCAM_DRIVERS="" CUSTOMER_LOGGING=1 /qnT="" INSTALL_SPU=2 CUSTOMER_LOGGING=0 /qn
Hi,
I'm struggling to get the syntax that runs with the MSI working above - I've worked with switches inside script blocks which invoke commands beforfe successfully but, not with those parameters which are from the program vendors help file.
I also tried:
Start-Process "msiexec.exe" -Argumentlist "/i "C:\smartmsi\SMART.msi" `
NB_PROD_KEY=NC-2ADA2-F9RKE-AKAIA-BBB ACTIVATE_LICENSE=1 INSTALL_INK="" LAT_CONTENT="" PRINT_CAPTURE="" INSTALL_DOCCAM_DRIVERS="" CUSTOMER_LOGGING=1 /qn
Totally confused how to install using the vendors commands within POwerShell, how can i nest each argument if it's not a switch?
I also tried using Splatter:
$params = '/i', "C:\smartmsi\SMART.msi",
'NB_PROD_KEY=NC-2ADA2-CEAM7-F9RKE', 'ACTIVATE_LICENSE=1',
'/qn'
& msiexec.exe #params
$LastExitCode
No joy - this app will install remotely as a regular install.
Thanks in advance
UPDATE:
Now, i've also tried this:
invoke-command -Session $session -ScriptBlock {
Start-Process -FilePath C:\windows\system32\msiexec.exe `
-ArgumentList "/i `"C:\smart\SMARTSuite.msi`" `"NB_PROD_KEY=NC-2ADA2`" ACTIVATE_LICENSE=1 INSTALL_INK=`"`" LAT_CONTENT=`"`" PRINT_CAPTURE=`"`" INSTALL_DOCCAM_DRIVERS=`"`" CUSTOMER_LOGGING=1 /qn"
}
Still not working. Installer appears for a second then drops off.
You have to escape `" if you want them to be interpreted inside a string which already uses double quotes else you break the string chaining :
Start-Process -FilePath msiexec -ArgumentList "/i `"C:\smartmsi\SMART.msi`" NB_PROD_KEY=NC-2ADA2-F9RKE-AKAIA-BBB ACTIVATE_LICENSE=1 INSTALL_INK=`"`" LAT_CONTENT=`"`" PRINT_CAPTURE=`"`" INSTALL_DOCCAM_DRIVERS=`"`" CUSTOMER_LOGGING=1 /qn"
You don't have to escape double quotes if the string is surrounded by simple quotes

Powershell Start-Process msiexec on a remote machine not working

For some reason Start-Process msiexec won't work when run through invoke command on a remote machine. I looked it up and while some people recommend using psiexec i have seen a lot of people using the plain old invoke-command to start msi installers on remote machines.
This is the code i am currently using:
$session = New-PSSession -computername $computerName -ea stop
$command = {
Param(
[Parameter()]
[string]$computerName,
[Parameter()]
[string]$domain,
[Parameter()]
[string]$user,
[Parameter()]
[string]$password,
[Parameter()]
[string]$installDir
)
$msiArgumentList = "/i C:\Installer.msi /l c:\log.txt /quiet /qr /norestart IAGREE=Yes DOMAIN=$domain ACCOUNT=$user PASSWORD=$password PASSWORDCONFIRM=$password INSTALLDIR=$installDir"
Start-Process msiexec -ArgumentList $msiArgumentList -Wait
}
Invoke-Command -session $session -ScriptBlock $command -ArgumentList $computerName, $domain, $user, $password, $installDir
Remove-PSsession -session $session
I used the same method to install services remotely using intallutil and it worked. Scripting is enabled on target machine as well as remoting so by all accounts it should work. Both computers have the same credentials but i still tried adding credentials to both invoke-command and the pssession. I tested the code locally and the installation worked. Remotely it doesn't and no errors what so ever. i can see on the target machine in taskmanager that msiexec is started but nothing happens. I even tried disabling the firewall and still nothing. i tried the & operator to start msiexec and still nothing.
Not sure what else i could try.
Maybe you try another way, if you don't come forward?
Use Task scheduler, to start the command line e.g by creating and executing a task on the remote machine:
SchTasks /CREATE /XML mycommand.xml /TN "thiscommand"
SchTasks /RUN /TN "thiscommand"
This is for starting a task (like) on the local computer.
With parameter /S you can create tasks on remote computers as in:
SchTasks /S thatPC /CREATE /XML mycommand.xml /TN "thiscommand"
SchTasks /S thatPC /RUN /TN "thiscommand"
For details of parameters and for syntax of the .xml file defining the task you can look into the help.
You could try executing Start-Process with Passthru to see if an error is being returned:
(Start-Process -FilePath msiexec.exe -ArgumentList $msiArgumentList -Wait -Passthru).ExitCode
The other thing that may help is increasing your logging to /l*v
Update 1
Can you try the following, just to check remote commands for msi are working, it should result in 1619.
(Start-Process -FilePath msiexec.exe -ArgumentList "/i no.msi /quiet /qb!" -Wait -Passthru).ExitCode
It seems the problem was a combination of how the msi installer was build and the restrictions windows server has towards interactive processes. I ended up using psexec to bypass this problem.
The only solution that worked for me was to poll the process status. This can be run inside a scriptblock in a remote powershell session.
$res = Start-Process -FilePath $process -ArgumentList $arguments -Wait -PassThru
while ($res.HasExited -eq $false) {
Write-Host "Waiting for $process..."
Start-Sleep -s 1
}
$exitCode = $res.ExitCode
Using the answers above I ended up with
$session = New-PSSession -ComputerName $serverName -Credential $mycred
invoke-command -Session $session -ScriptBlock { param ($argxs) write-host $argxs; start-process msiexec.exe -ArgumentList $argxs } -ArgumentList "/i `"$pathToMsi`" /qn /L*V `"E:\package.log`""
The write-host is just there to verify the augments are correctly escaped but proved invaluable in debugging.