Using Advanced installer, I've created a package resulting in an EXE (there are deployment features that couldnt be contained within a plain MSI file).
Now, while Advanced Installer allows me to pass through command line parameters to the underlying MSI, I have no idea what parameters to pass to force the package to uninstall.
For example, the following parameters logs the setup events and instructs the underlying MSI to run passively and log its own actions.
"c:\MySetup.exe" /exelog "c:\log.txt" /passive /log "c:\msilog.txt"
The resulting commands that AdvancedInstaller executes is ultimately
msiexec.exe /i [path to extracted msi] /passive /log "c:\msilog.txt"
But try as I might, I cannot figure out how to have AdvancedInstaller launch msiexec with the /uninstall or the /x switch. For example:
"c:\MySetup.exe" /exelog "c:\log.txt" /x /log "c:\msilog.txt"
results in
msiexec.exe /i [path to extracted msi] /x /passive /log "c:\msilog.txt"
which of course fails because the /x is in the wrong place (should be in place of the /i).
What switches/parameters is the Advanced Installer exe needing?
Ok, it was buried a little obscurely in the documentation:
All 'pre-path-to-msi' parameters follow a "[option] // [optional parameters]" pattern
The following will instruct the Advanced Installer EXE bootstrap to fire off the MSI as uninstall.
UPDATED:
"c:\MySetup.exe" /exelog "c:\log.txt" /x // /log "c:\msilog.txt"
You can use the // marker, for example:
"c:\MySetup.exe" /exelog "c:\log.txt" /x // /log "c:\msilog.txt"
This marker is used to replace the msiexec command line. You can read about it in the user guide: http://www.advancedinstaller.com/user-guide/exe-setup-file.html
Related
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.
I'm currently trying to run a batch file as a startup script to detect and remove whatever version of office a user has installed and then to install Office 365. I have the install working however, when I attempted to uninstall Office 2013 I received the following error:
Input Error: Can not find script file "C:\Windows\OffScrub_O15msi.vbs"
The Offscrub file is in the same location as the script, is someone able to tell me why it's looking in C:\Windows for it?
Update
Please find my current script which now works for Office 2013, I previously added the line Remove2016Installs $true when using -Command to remove Office 2016, this worked. Since using -File to work around my initial problem I've been unable to get the script to remove Office 2016 and would like some advice on how to do this, I've read that whatever command is after -File needs to be the last which I believe might be why it's failing.
My full script is below:
start "----NOTICE----" cmd.exe /t:ec /Q /k "echo OFFICE 365 IS BEING INSTALLED. THIS WINDOW WILL CLOSE WHEN COMPLETE&&prompt $h"
#echo off
pushd "%~dp0"
powershell.exe -executionpolicy bypass -NoExit -File "Remove-PreviousOfficeInstalls.ps1"
popd
reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set OS=32BIT || set OS=64BIT
if %OS%==32BIT "\\domain\SYSVOL\domain\Policies\{Policy Number}\Machine\Scripts\Startup\setup.exe" /configure "\\domain\SYSVOL\domain\Policies\{Policy Number}\Machine\Scripts\Startup\configuration-Office365-x86.xml"
if %OS%==64BIT "\\domain\SYSVOL\domain\Policies\{Policy Number}\Machine\Scripts\Startup\setup.exe" /configure "\\domain\SYSVOL\domain\Policies\{Policy Number}\Machine\Scripts\Startup\configuration-Office365-x64.xml"
taskkill /IM cmd.exe /FI "WINDOWTITLE EQ ----NOTICE----"
taskkill /IM cmd.exe /FI "WINDOWTITLE EQ Administrator: ----NOTICE----"
echo %date% %time% Setup ended with error code %errorlevel%. >> %LogLocation%\%computername%.txt
Update Finished
There's a line that calls the Powershell script Remove-PreviousOfficeInstalls, this is a file from GitHub that is very popular for the removal of whichever Office version you have installed.
I can run this command if say I copy these files to the desktop and amend the locations in the scripts, I'm not sure what this reference to C:\Windows is though when run from \domain\SYSVOL\domain\Policies{Policy Number}\Machine\Scripts\Startup\?
If you run a default instances of PowerShell it always starts in a certain directory. It depends on how and who it is started by. For instance an administrative PowerShell usually starts in C:\Windows\System32. If you use any paths that are not absolute they're applied relative to this directory.
To work around this you need to change the directory it's using. For instance by using cd to change the directory. My guess would be that your script Remove-PreviousOfficeInstalls.ps1 contains a relative call to the VBS.
An easy fix would be to run a script block instead of a single command and just cd to \\domain\SYSVOL\domain\Policies\'{Policy Number}'\Machine\Scripts\Startup\ prior to running the ps1.
The PowerShell help you can view by following [this] link or running powershell -h has the following information in regards to using the -Command switch.
...
Script blocks must be enclosed in braces ({}). You can specify a script block only when running PowerShell.exe in PowerShell. If you want to use a script block when running from another shell you must use the format:
"& {}"
...
The other important parameter for your use case is -File.
Runs the specified script in the local scope ("dot-sourced"), so that the functions and variables that the script creates are available in the current session. Enter the script file path and any parameters.
...
Your batch contains the following line:
powershell.exe -executionpolicy bypass -Command "\\domain\SYSVOL\domain\Policies\'{Policy Number}'\Machine\Scripts\Startup\Remove-PreviousOfficeInstalls.ps1 -Remove2016Installs $true"
What you do is run a single command to invoke a script with a parameter. The problems is that said script checks its locations based on certain function and with your invocation that location is wrongly detected.
There are multiple ways to fix this. One would be to change the directory before invoking the script. To do this you'd need to use a script block as the parameter for -Command. An example for this would be:
powershell.exe -Command "& {Write-Output 'Hello'; Write-Output 'World';}"
As you can see there are two independent Write-Output commands being run. You'd change this to a cd \\domain\SYSVOL\domain\Policies\'{Policy Number}'\Machine\Scripts\Startup\ and the invocation of your script. As a bonus you wouldn't need to put the whole path in front of the script anymore.
The other option would be to run powershell -File with your current invocation of the script. That should also mean that the script is read from the file and the corresponding parameters are populated accordingly.
If neither of these options work you will have to check what $PSScriptRoot is being populated with and/or what the return of (Get-Item -Path ".\").FullName is as those are the two commands used to determine the location of the script that's being executed. To do this you could use a script block.
thanks for your help regarding this. My resolution was to use the following bat command:
`start "----NOTICE----" cmd.exe /t:ec /Q /k "echo OFFICE 365 IS BEING INSTALLED. THIS WINDOW WILL CLOSE WHEN COMPLETE&&prompt $h"`
#echo off
pushd "%~dp0"
powershell.exe -executionpolicy bypass -File Remove-PreviousOfficeInstalls.ps1 -Remove2016Installs
popd
reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set OS=32BIT || set OS=64BIT
if %OS%==32BIT "\\Server\Folder\Folder\setup.exe" /configure "\\Server\Folder\Folder\configuration-Office365-x86.xml"
if %OS%==64BIT "\\Server\Folder\Folder\setup.exe" /configure "\\Server\Folder\Folder\configuration-Office365-x64.xml"
taskkill /IM cmd.exe /FI "WINDOWTITLE EQ ----NOTICE----"
taskkill /IM cmd.exe /FI "WINDOWTITLE EQ Administrator: ----NOTICE----"
echo %date% %time% Setup ended with error code %errorlevel%. >> %LogLocation%\%computername%.txt
I had to amend the Remove-PreviousOfficeInstalls powershell script to include the switch command:
[Parameter(ValueFromPipelineByPropertyName=$true)]
[switch]$Remove2016Installs = $false,
This then did exactly what I was after, it detected the current version of Office, removed it and installed the correct bit version of Office 365 for that PC\Laptop.
Thanks for all your help
I am trying to execute the following command through powershell, in a script invoked by an Advanced Installer generated installation program. The problem is that when the script executes, it chokes on a call to MSIEXEC.exe. More specifically, it puts up a windows dialog of the msiexec help screen.
Ok so maybe it doesn't like the way advanced installer is executing it. So I take the actual line that is causing problems:
msiexec.exe /q /i 'C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi' INSTALLLOCATION='C:\Program Files\MongoDB\Server\3.4\' ADDLOCAL='all'
And when I execute this directly in powershell, I still get the same stupid help screen. I have tried every conceivable variation of this command line:
/a and /passive instead of /i and /q
with double quotes
with single quotes
the msi unquoted
in an admin elevated shell
in a normal privilege shell
the msi located on the desktop instead of the temp folder
using /x to uninstall in case it was already installed
In all cases, I get the damnable "help" dialog. The only thing that appears to make a difference is if I leave off the INSTALLLOCATION and ADDLOCAL options. (These are apparently used as per "Unattended Installation part 2" found here: https://docs.mongodb.com/tutorials/install-mongodb-on-windows/). In that case it just exits quietly without installing anything.
I'm honestly at my wits' end having been beating my head against the wall on this all afternoon.
By the way, the reason I'm installing mongo in such an absurd way is I need a method of having a single-install system for my company's product. It depends on Mongo, and we have to have it run as a server and use authentication, so I have to have scripts to create the admin and database user and put it into authenticated mode. Since I needed to know where mongo was installed (to execute mongod.exe and mongo.exe) I need to query the user first for the location, then pass on the install location to the mongo installer. If I'm completely off the rails here please let me know that there's a better way.
Thanks
EDITED: I forgot to mention I wrote my complete powershell script and tested it before trying to execute it through advanced installer. The script worked until I tried to run it through the installer. Strange that I still can't execute the command though manually now.
It seems that in order to pass paths with embedded spaces to msiexec, you must use explicit embedded "..." quoting around them.
In your case, this means that instead of passing
INSTALLLOCATION='C:\Program Files\MongoDB\Server\3.4\', you must pass INSTALLLOCATION='"C:\Program Files\MongoDB\Server\3.4\\"'[1]
Note the embedded "..." and the extra \ at the end of the path to ensure that \" alone isn't mistaken for an escaped " by msiexec (though it may work without the extra \ too).
To put it all together:
msiexec.exe /q /i `
'C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi' `
INSTALLLOCATION='"C:\Program Files\MongoDB\Server\3.4\\"' ADDLOCAL='all'
Caveat:
This embedded-quoting technique relies on longstanding, but broken PowerShell behavior - see this answer; should it ever get fixed, the technique will stop working; by contrast, the
--% approach shown below will continue to work.
A workaround-free, future-proof method is to use the PSv3+ ie helper function from the Native module (in PSv5+, install with Install-Module Native from the PowerShell Gallery), which internally compensates for all broken behavior and allows passing arguments as expected; that is, simply prepending ie to your original command would be enough:
# No workarounds needed with the 'ie' function from the 'Native' module.
ie msiexec.exe /q /i 'C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi' INSTALLLOCATION='C:\Program Files\MongoDB\Server\3.4\' ADDLOCAL='all'
The alternative is to stick with the original quoting and use --%, the stop-parsing symbol, but note that this means that you cannot use PowerShell variables in all subsequent arguments:
msiexec.exe /q /i `
'C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi' `
--% INSTALLLOCATION="C:\Program Files\MongoDB\Server\3.4\\" ADDLOCAL='all'
Note that msiexec, despite having a CLI (command-line interface), is a GUI-subsystem application, so it runs asynchronously by default; if you want to run it synchronously, use
Start-Process -Wait:
$msiArgs = '/q /i "C:\Users\ADMINI~1\AppData\Local\Temp\mongo-server-3.4-latest.msi" INSTALLLOCATION="C:\Program Files\MongoDB\Server\3.4\\" ADDLOCAL=all'
$ps = Start-Process -PassThru -Wait msiexec -ArgumentList $msiArgs
# $ps.ExitCode contains msiexec's exit code.
Note that the argument-list string, $msiArgs, is used as-is by Start-Process as part of the command line used to invoke the target program (msiexec), which means:
only (embedded) double-quoting must be used.
use "..." with embedded " escaped as `" to embed PowerShell variables and expressions in the string.
conversely, however, no workaround for partially quoted arguments is needed.
Even though Start-Process technically supports passing the arguments individually, as an array, this is best avoided due to a longstanding bug - see GitHub issue #5576.
[1] The reason that INSTALLLOCATION='C:\Program Files\MongoDB\Server\3.4\' doesn't work is that PowerShell transforms the argument by "..."-quoting it as a whole, which msiexec doesn't recognize; specifically, what is passed to msiexec in this case is:
"INSTALLLOCATION=C:\Program Files\MongoDB\Server\3.4\"
I am trying to install “azure-powershell.0.8.7.msi” through a .cmd file using command
msiexec.exe /i ".\azure-powershell.0.8.7.MSI" /passive
This msi file is part of solution explorer(part of project, I have to do it in this way only).
Although I am able to install/uninstall when this msi file when it’s on local disk ( i.e. on some drive)
I tried to log the error it 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.”
It is a known error of Microsoft. I tried each and every proposed solution on internet but it doesn’t work.
Note: The current user/admin of the system have all the access(read,write,modify).
if your MSI-file is in the same directory like the cmd-file you have to us the following command
msiexec /i "%~dp0azure-powershell.0.8.7.MSI" /qb
%~dp0 is refering to cmd-file directory and in this case to the MSI-file.
If you want to create a log-file use the /l and the logfilepath plus name after /qb.
For example:
msiexec /i "%~dp0azure-powershell.0.8.7.MSI" /qb /l*v %temp%\azure-powershell.log
I have a batch file, which exists as soon as start it (run as admin) and does not execute commands that are in it, but if I specify it at the command-line, it runs fine and executes all commands.
Here's what's in it:
start /wait msiexec /x SetupServices.msi /qn /l* "SetupServices.uninstall.log"
start /wait msiexec /i SetupServices.msi /qn /l* "SetupServices.install.log"
(Corrected answer)
First, if you start .exe files in a batch, it is safer, to prefix it with "call".
Sometimes this is necessary to assure, that the batch is waiting to complete.
Using "start" is another possibility, but for this simple usecase not necessary.
You write that the commands are not executed. So, obviously, you have another problem, instead of the "does not wait.. to complete" problem.
Taking a look of your newly provided example, this is the case. In admin mode, you have to provide a full path. With my small trick below ("%~dp0", including already backslash), you can still use the current directory in batchfiles.
Most times, if such a problem occurs with admin rights, this is a problem of the "current directory" path. A batch file with admin rights is not using it in the same way as we were used to, it does not start in it's own directory (but in System32 mostly). Not relying on the CD is an important matter of writing bullet-proof batch files.
A good example batch , combining other answers here, and solving a number of possible problems in your case is:
call msiexec /i "%~dp0MySetup.msi" /qb /L*v "%~dp0MySetup.log"
echo Returncode: %ERRORLEVEL%
pause
It uses the current directory correctly, and assumes an install commandline including a logfile (works only, if you have write access in the current directory, if not specify a path for the logfile with write access like "%TEMP%\MySetup.log".
Attention: Remember to really start the batch file with admin rights (right mouse menu or opening an admin command shell before:)
Coming back to this question I think the "correct way" to do it is via PowerShell
Start-Process -Wait -FilePath msiexec -ArgumentList /i, "setup.msi", /qn, /l*v, "install.log"
Or just prefix it with PowerShell; to invoke directly from CMD
PowerShell; Start-Process -Wait -FilePath msiexec -ArgumentList /i, "setup.msi", /qn, /l*v, "install.log"
No hacks and no tricks :-)
Try taking the start /wait out for the msiexec lines, if that doesn't work create two more bat files one called uninstall.bat the other install.bat and use call to execute them in series.
It goes a little beyond the question, but an extension to my answer concerning handling the current directory: Here is my recommended beginning for every batch file conserving it's own path. The specialty is that it also works for UNC paths. "Pushd" automatically creates a new drive letter, if necessary (assumed, you have one free of 26). Of course you can use "popd" also at the end of the batch file instead immediately, but stable commands do not rely on the current directory as I mentioned, so it is better to always provide full paths.
#echo off
cls
pushd %~dp0
popd
set MYDIR=%CD%
echo Directory of this batch fil: %MYDIR%
You can then add the msi lines from the other answer like this:
call msiexec /i "%MYDIR%\MySetup.msi" /qb /L*v "%MYDIR%\MySetup.log"
echo Returncode: %ERRORLEVEL%
pause
(Remark: For the logfile path of course you are free, it has not to be necessarily in the same directory. But good for testing/debugging. In every case you have to have write access to the directory/file you are giving MSI with.)
While for normal MSI files it is not always necessary to start the batch with admin rights from the beginning, this technique is by far more safe (to start the MSI like already with admin rights) than too rely on the MSI UAC coming later (maybe).
And it works with msiexec ... /qn too, which is important (silent installs).
Add pause statement to the end of the batch, this will prevent the console window from closing and you will be able to see error messages if any. Errors could be the reason why it exits without actually running anything. What kind of error it may be? SetupServices.msi is not found — that's what comes to my mind.
Needs the "Window Title" if you use Parameter
start /wait "Window Title" "MsiExec.exe" /i SetupServices.msi /qn /l* SetupServices.uninstall.log
start /wait "Window Title" "MsiExec.exe" /i SetupServices.msi /qn /l* SetupServices.install.log