msiexec Powershell silent install - powershell

I am searching for a Powershell Script which allows me to silent install a msi file.
We have over 25000 PCs so i have to do that with a script.
Unfortunately at the moment a window popping up (Windows Installer) after the execution which shows the parameter of a msi file. Nothing more, no other "error messages" are popping up.
The first thing the Script should do is to check if the PC is a Desktop or Mobile Device.
If its a Desktop device he should write in a file "Desktop Configuration was used".
In the same time the msi installer should start with some parameter.
If its a Laptop the procedure should be nearly the same.
After the installation is successful the user should be signed out.
I need this script to implement 2FA in our company.
The code at the moment looks like this:
IF ( ((Get-ComputerInfo | select -expand CsPCSystemType) -LIKE "Desktop") )
{
Write-Output "Desktop Configuration was used." >> \\XXX\XXX\XXX\XXX\Log\$env:Computername.txt
msiexec.exe /i "%~dp0setup.msi" /passive /norestart /L*v "%~dp0setup.log"
}
ELSE {
Write-Output "Laptop Configuration was used." >> \\XXX.XXX.XX\X\XX\XXX\XXXX\$env:Computername.txt
msiexec.exe /i "%~dp0setup.msi" /passive /norestart /L*v "%~dp0setup.log"
}
Write-Output "Lock Configuration was used." >> \\XXX\XXX\XXX\XXX\Log\$env:Computername.txt
rundll32.exe user32.dll,LockWorkStation
Any help is really appreciated.

The token %~dp0 (which resolves to the directory where the current script resides in) only works in batch scripts.
In PowerShell, replace $~dp0 by $PSScriptRoot. That should solve the problem of msiexec showing up with the available command-line options.
Another problem of your script is that msiexec runs asynchronously, when called directly as a command. So your script will be finished while the installation is still running, which is propably not what you want. This is caused by msiexec.exe being a GUI application. To run GUI applications synchronously, use Start-Process -Wait.
$Arguments = "/i", "`"$PSScriptRoot\setup.msi`"", "/passive", "/norestart", "/L*v", "`"$PSScriptRoot\setup.log`""
$msiProcess = Start-Process msiexec.exe -Wait -ArgumentList $Arguments -PassThru
# Check if installation was successful
# 0 = ERROR_SUCCESS, 3010 = ERROR_SUCCESS_REBOOT_REQUIRED
if( $msiProcess.ExitCode -in 0, 3010 ) {
Write-Host "Installation succeeded with exit code $($msiProcess.ExitCode)"
}

Try passing silent switches (/qn! or /qb!) instead of /passive flag.

Related

Powershell Elevated and pass a command

So I am building a script that launches an executable in the common files folder of x86 folder. The issue I am having is the script uses the (x86) as if the x86 is a command that should be run first. Does anyone have any ideas on how to prevent that?
$Pulse = "${env:CommonProgramFiles(x86)}\Pulse Secure\JamUI\JamCommand.exe"
$ImportFile = '"-importfile "C:\Program Files (x86)\MyFile.preconfig"'
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{Start $Pulse, $ImportFile}" -Verb Runas
As Mathias notes, there is no strict need to launch another PowerShell instance with elevation (run as admin, -Verb RunAs), because you can directly elevate the target executable, JamCommand.exe; however, if you want to run the executable in another PowerShell session that stays open afterwards - as your use of -noexit suggests - you indeed do:
$pulse = "${env:CommonProgramFiles(x86)}\Pulse Secure\JamUI\JamCommand.exe"
$importFileArg = '-importfile "C:\Program Files (x86)\MyFile.preconfig"'
Start-Process -Verb RunAs powershell #"
-noexit -noprofile -c & "$pulse" $importFileArg
"#
Note:
This runs JamCommand.exe directly in the elevated PowerShell session, synchronously (assuming it is a console application), and the interactive session is only entered after that program exits. (Your attempt contains another Start-Process call (via alias Start), which would make a console program run in yet another console window, which auto-closes when the program exits.)
All pass-through arguments are encoded in a single (here)-string passed to the (positionally implied) -ArgumentList parameter, which allows direct control of the command line that is used to launch process, and is generally the most robust approach due to a long-standing bug in how passing arguments individually, as elements of an array is handled - see this answer.

Trying to run a headless executable command through Powershell that works on cmd line

I am trying to run an executable through powershell to run headless, to install a program onto a VM/LocalHost machine. I can get the wizard to open, but for whatever reason I cannot get it to run headless. Here is the cmd line that I run that works:
start /WAIT setup.exe /clone_wait /S /v" /qn"
This is my attempts in powershell
Start-Process .\setup.exe /S -Wait -PassThru
Start-Process .\setup.exe /S /v /qn -Wait -PassThru
Start-Process setup.exe -ArgumentList '/clone_wait /S /v /qn' -Wait
In the cmd line instance the application installs without issue - in the powershell instance the wizard opens and is on the first "Next" prompt. Any help would be appreciated!
I also attempted to add the additional parameters "/v" and "/qn" which return an error : Start-Process : A positional parameter cannot be found that accepts argument '/v'
The bottom attempt runs but it's not waiting for the installation to complete
You may be overthinking it. Remember that PowerShell is a shell. One of the purposes of a shell is to run commands that you type.
Thus: You don't need Start-Process. Just type the command to run and press Enter.
PS C:\> .\setup.exe /clone_wait /S /v /qn
Now if the executable (or script) you want to run contains spaces in the path or name, then use the call/invocation operator (&) and specify the quotes; for example:
PS C:\> & "\package files\setup.exe" /clone_wait /S /v /qn
(This behavior is the same no matter whether you are at the PowerShell prompt or if you put the command in a script.)
This worked for me. You need to quote the whole argumentlist, plus embed double quotes to pass what you want to /v.
start-process -wait SetupStata16.exe -ArgumentList '/s /v"/qb ADDLOCAL=core,StataMP64"'
Running the command normally and then using wait-process after might be a simpler alternative, if you're sure there's only one process with that name:
notepad
wait-process notepad
To follow-up to all that you have been given thus far. Running executables via PowerShell is a well-documented use case.
PowerShell: Running Executables
Solve Problems with External Command Lines in PowerShell
Top 5 tips for running external commands in Powershell
Using Windows PowerShell to run old command-line tools (and their
weirdest parameters)
So, from the first link provides more validation of what you've been given.
5. The Call Operator &
Why: Used to treat a string as a SINGLE command. Useful for dealing with spaces.
In PowerShell V2.0, if you are running 7z.exe (7-Zip.exe) or another command that starts with a number, you have to use the command invocation operator &.
The PowerShell V3.0 parser do it now smarter, in this case you don’t need the & anymore.
Details: Runs a command, script, or script block. The call operator, also known as the "invocation operator," lets you run commands that are stored in variables and represented by strings. Because the call operator does not parse the command, it cannot interpret command parameters
Example:
& 'C:\Program Files\Windows Media Player\wmplayer.exe' "c:\videos\my home video.avi" /fullscreen
Things can get tricky when an external command has a lot of parameters or there are spaces in the arguments or paths!
With spaces you have to nest Quotation marks and the result it is not always clear!
In this case it is better to separate everything like so:
$CMD = 'SuperApp.exe'
$arg1 = 'filename1'
$arg2 = '-someswitch'
$arg3 = 'C:\documents and settings\user\desktop\some other file.txt'
$arg4 = '-yetanotherswitch'
& $CMD $arg1 $arg2 $arg3 $arg4
# or same like that:
$AllArgs = #('filename1', '-someswitch', 'C:\documents and settings\user\desktop\some other file.txt', '-yetanotherswitch')
& 'SuperApp.exe' $AllArgs
6. cmd /c - Using the old cmd shell
** This method should no longer be used with V3
Why: Bypasses PowerShell and runs the command from a cmd shell. Often times used with a DIR which runs faster in the cmd shell than in PowerShell (NOTE: This was an issue with PowerShell v2 and its use of .Net 2.0, this is not an issue with V3).
Details: Opens a CMD prompt from within powershell and then executes the command and returns the text of that command. The /c tells CMD that it should terminate after the command has completed. There is little to no reason to use this with V3.
Example:
#runs DIR from a cmd shell, DIR in PowerShell is an alias to GCI. This will return the directory listing as a string but returns much faster than a GCI
cmd /c dir c:\windows
7. Start-Process (start/saps)
Why: Starts a process and returns the .Net process object Jump if -PassThru is provided. It also allows you to control the environment in which the process is started (user profile, output redirection etc). You can also use the Verb parameter (right click on a file, that list of actions) so that you can, for example, play a wav file.
Details: Executes a program returning the process object of the application. Allows you to control the action on a file (verb mentioned above) and control the environment in which the app is run. You also have the ability to wait on the process to end. You can also subscribe to the processes Exited event.
Example:
#starts a process, waits for it to finish and then checks the exit code.
$p = Start-Process ping -ArgumentList "invalidhost" -wait -NoNewWindow -PassThru
$p.HasExited
$p.ExitCode
#to find available Verbs use the following code.
$startExe = new-object System.Diagnostics.ProcessStartInfo -args PowerShell.exe
$startExe.verbs

Install Multiple msi files consecutively

I have just recently started using (and learning how to) script. I am using Powershell ISE and am trying to create a script that can be run on a new computer to install multiple/various programs. I have the programs in both .exe and .msi and want the programs to install silently, and consecutively. Again I am a beginner, but have put together the script below to get this done. I am trying to find out what variable/command will ensure that the programs install one by one.
msiexec.exe /q /i '\\Server\Folder\Applications\msi files\file.msi'
msiexec.exe /q /i '\\Server\Folder\Applications\msi files\file.msi'
msiexec.exe /q /i '\\Server\Folder\Applications\msi files\file.msi'
msiexec.exe /q /i '\\Server\Folder\Applications\msi files\file.msi'
msiexec.exe /q /i '\\Server\Folder\Applications\msi files\file.msi'
msiexec.exe /q /i '\\Server\Folder\Applications\msi files\file.msi'
I originally started this as a .bat file, and can run it to install the .exe files just fine, however they all run at the same time. Therefore, I figured creating a script (rather than a .bat file) would be my best bet. Any and all input and or help is greatly appreciated!
You cannot run multiple .msi files all at once if that's what you're wanting. If you want to run them consecutively it would look like this in Powershell:
If it's an msi:
Start-Process msiexec.exe -Wait -ArgumentList '/I ProgramName.msi /quiet'
If it's an exe:
Start-Process programname.exe -Wait -ArgumentList '/I /quiet'
And basically the -Wait parameter will wait until the windows installer closes until it proceeds to the next line of code. Some msi's do have different ways of classifying args depending on the developer. Sometimes it's /q, /qn or /quiet.
Windows Installer: the msiexec.exe engine should wait for your installation to complete before it exits. I suspect your command lines are wrong and that is why it looks like they all run and exit simultaneously.
Sample Command Line: Maybe try this command line (maybe put in MyTest.cmd and run):
msiexec.exe /i MySetup.msi /L*V C:\MyLog.log /qn ADDLOCAL=ALL REBOOT=ReallySuppress ALLUSERS=1
Repeat command line for each MSI you need to install.
Logging:The log files should have unique names, obviously. You can enable logging for all MSI installations (section 'Globally for all setups on a machine'). Then you will find a new MSI-log file with a random name in the system's %TEMP% folder after each MSI operation. Sort by change date to find the latest one. To find errors in MSI logs, try searching for "value 3".
More information available on request. Please do NOT add your own answer, edit your original question instead. Just add more info, delete or whatever you need. We have versioning so we can find what you delete as well if need be.

How can I make PowerShell wait until a command is complete before proceeding?

I'm using the following line to uninstall office 2007 based on its Product ID
Start-Process C:\Windows\System32\msiexec.exe -ArgumentList "/uninstall {90120000-0030-0000-0000-0000000FF1CE}"
I'd like to force a reboot after the uninstall is complete however using -Wait or piping the results to Out-Null don't wait until the uninstall is complete before processing the next line which is a restart. I've also tried using cmd to uninstall but with the same result.
cmd /c "msiexec.exe /uninstall {90120000-0030-0000-0000-0000000FF1CE}"
Is there any way to force powershell to wait until the uninstall is complete before processing the Restart-Computer command? I was thinking possibly writing something that detects when the setup.exe process stops before proceeding to the restart?
Start-Process has a wait parameter:
Start-Process C:\Windows\System32\msiexec.exe -ArgumentList "/uninstall {90120000-0030-0000-0000-0000000FF1CE}" -wait
The solution to restart after an misexec.exe uninstallation is to add the /forcerestart parameter to the msiexec call instead of trying to restart in powershell (Credits to Matt):
Start-Process C:\Windows\System32\msiexec.exe -ArgumentList #("/uninstall {90120000-0030-0000-0000-0000000FF1CE}", "/forcerestart")
The simplest workaround: pipe the result. This will force a wait until the process is finished.
No need for start-process or cmd.
You could pipe to out-default, out-file, out-null or out-host, depending on how you want to handle the output. (If you don't care about the output, simply use out-null.)
& msiexec.exe /uninstall "{90120000-0030-0000-0000-0000000FF1CE}" | Out-Null
My suggestion for this is to actually get the Office Removal Tool from Microsoft and extract the VBS script from it. Run that in a Start-Process with the -wait argument, and reboot afterwards. It will not only attempt to gracefully remove Office with msiexec as you are doing, it will also go back and clean up any straggling files or registry entries in case the application is corrupt and will not uninstall nicely.

Powershell uninstall program with msiexec

I've run into a problem getting msiexec to remove java with Powershell. I've output my resultant command to the screen and pasted it into a batch file and it runs great. But when it's executed via Powershell it fails saying the "package cannot be found". Can anyone spot what I might be doing wrong? I've looked up and down google and tried a few different ways of executing the command w/o success and with the same result.
cls
$java = Get-WmiObject -Class win32_product | where { $_.Name -like "*Java*"}
$msiexec = "c:\windows\system32\msiexec.exe";
#$msiexecargs = '/x:"$app.LocalPackage" /qr'
$msiexecargs = '/uninstall "$app.IdentifyingNumber" /qr /norestart'
if ($java -ne $null)
{
foreach ($app in $java)
{
write-host $app.LocalPackage
write-host $app.IdentifyingNumber
#&cmd /c "msiexec /uninstall $app.IdentifyingNumber /passive"
#Start-Process -FilePath $msiexec -Arg $msiexecargs -Wait -Passthru
[Diagnostics.Process]::Start($msiexec, $msiexecargs);
}
}
else { Write-Host "nothing to see here..." }
Write-Host "check end"
The goal is to use the Windows 7 logon script to remove all versions of Java on end-user systems and then install the latest. I prefer to make it all Powershell, but if I can't get this working I'll just use a batch file hard coded with the uninstall GUID's
The write-host statements are all for the purpose of debugging, I'm just interested in the execution of msiexec in some variation of this format: msiexec /x {GUID} /passive /norestart
The error I get is:
"This installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package."
I know it works on its own, just not in this script...so I'm thinking it's a syntax thing.
If you have any questions let me know.
First you have to know the difference between this:
"$app.IdentifyingNumber"
and this
"$($app.IdentifyingNumber)"
So I think you wanted to use the latter (the code is a little bit confusing because of the commented lines):
&cmd /c "msiexec /uninstall $($app.IdentifyingNumber) /passive"