Is it possible to disable msiexec help GUI?
Solution 1:
There is no way to disable this behavior for an msiexec
command containing a syntax error. You could wrap the command into something like the following. It uses .NET Automation to look for the "usage" window and deal with it in-script.
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes
# Note the invalid argument '/badswitch'
$mse = Start-Process -FilePath 'msiexec' -ArgumentList "/i package.msi /badswitch /quiet /passive" -PassThru
# Let msiexec at least get off the ground
[void] $mse.WaitForInputIdle()
# Create an AutomationElement from $mse's handle
$mseAuto = [Windows.Automation.AutomationElement]::FromHandle($mse.MainWindowHandle)
# A PropertyCondition for findAll()
$pane = New-Object Windows.Automation.PropertyCondition -ArgumentList (
[Windows.Automation.AutomationElement]::ControlTypeProperty,
[Windows.Automation.ControlType]::Pane
)
# Search for a child $pane element.
$findResult = $mseAuto.FindFirst(
[System.Windows.Automation.TreeScope]::Children,
$pane
)
# If there's a pane element in $mseAuto, and it contains "usage" string, it's an msiexec syntax issue, so close $mse's window.
if ( $findResult.Current.Name -match 'msiexec /Option <Required Parameter>' ) {
[void] $mse.CloseMainWindow()
} else {
# You should put something more sane here to handle waiting for "good" installs to complete.
$mse.WaitForExit()
}
$mse.ExitCode
This too has problems. With /quiet
a progress dialog is still displayed during install. You may consider using /qn
instead would hide all msiexec
UI elements. As well the MSI may trigger other errors, unhandled, which would pause execution infidelity. Perhaps include a time out value? And what of external process launched from the CustomAction table? Sorry, I'm close to rambling now...
Solution 2:
Sadly, I think the only way to avoid the help display is to...
...not make any typos/syntax errors.
I wish I had a better answer for you, but...
Solution 3:
I would just avoid going via msiexec.exe altogether. This is possible by going via the Windows Installer API using scripts or code.
You can go via COM automation using VBScript / VBA / VB, or using DTF which is a .NET wrapper for the Windows Installer API that's easier to work with from .NET languages such as C#.
You could even go directly via C++ to the raw Win32 API calls, but that's just a waste of time since you have both COM and .NET equivalents that call the raw Win32 API as part of their operation.
Solution 1: VBScripts and COM Automation
If using automation is an option you should be able to go via the Windows Installer COM automation and automate installation / uninstallation that way. Here is a VBScript you can put in a file and run (update the MSI path name obviously):
Const msiUILevelEndDialog = 128
Set msi = CreateObject("WindowsInstaller.Installer")
msi.UILevel = msiUILevelEndDialog
msi.InstallProduct( "C:\msifile.msi")
Set msi = Nothing
Solution 2: DTF - Deployment Tools Foundation - .NET
DTF (Deployment Tools Foundation) is essentially a .NET wrapper for the Windows Installer API - it features such a powerful collection of .NET assemblies to work directly with aspects of Windows Installer, that I just want to add it here for reference for those who search for a solution with a lot of fine-grained deployment control to solve their administration problem. Very simple code inside a C# application provides full control of the installation process. Here is a rough mock-up:
using Microsoft.Deployment.WindowsInstaller.Installer;
Installer.SetInternalUI(InstallUIOptions.Silent);
Installer.InstallProduct(msiFilename, "ACTION=INSTALL ALLUSERS=1");
You can get hold of DTF via the WIX toolkit - which is an overall solution for creating MSI files from XML source files. You will find excellent documentation in DTF.chm and DTFAPI.chm and the actual files are in the main installation folder. The two last ones are generally the ones you need:
- Microsoft.Deployment.Compression.dll - Framework for archive packing and unpacking.
- Microsoft.Deployment.Compression.Cab.dll - Implements cabinet archive packing and unpacking.
- Microsoft.Deployment.Resources.dll - Classes for reading and writing resource data in executable files.
- Microsoft.Deployment.WindowsInstaller.dll - Complete class library for the Windows Installer APIs.
- Microsoft.Deployment.WindowsInstaller.Package.dll - Extended classes for working with Windows Installer installation and patch packages.
Just create a C# project, reference these files, and code your own deployment application with whatever control you desire and need. I am not set up with the tools for DTF at the moment, but see this sample for a general idea of how a C# program would work.
Solution 3: C++ Installer Functions
I just figured I'd add this - it is largely irrelevant for system administrators I believe, but it might help to understand the MSI technology better. Besides COM automation, there is also a Win32 API with functions accessible from C++. Much better performance of course (the COM automation obviously calls these Win32 functions under the hood - COM is just a wrapper on top of these "real" functions of course).
I don't have any C++ samples available for this right now, but here is the SDK documentation: Windows Installer Reference. And a direct link to the list of actual installer functions. This list of functions should give you a quick idea of what it is like to use this technology.
UPDATE: I added a C++ snippet sample in this stackoverflow answer on different ways to uninstall an MSI package (section 14 at the bottom of the answer).
System administrators wouldn't use this option, but commercial tools would in order to access the system's MSI database (stored in a few locations in the registry and with a cache folder on disk - %SystemRoot%\Installer
- and some "working folders"). For example your SCCM or similar deployment system will use them "under the hood".
Solution 4: WMI
Just adding that there are a few WMI classes that can be used to automate and query MSI. Win32_Product and a couple of other ones.