Monday, August 15, 2011

MSIExec Exit Codes in Script

I could have left off the "in Script" part, but whatever.  Since I'm talking about this in the context of scripting I suppose it fits.  If you do any packaging (or more accurately: re-packaging) of software installations, you should bookmark Microsoft Support Article 229683.  This article provides a useful index of MSIEXEC exit codes and what they represent.

There are a few that should look familiar, but some of you may not be aware of them.  The longer you work with deploying software (and software uninstalls), especially via script, the more likely you will encounter these particular exit codes at some point.  There are others that pop up, but these tend to be the most common...

0 (zero) - represents "good", or "no errors".  In general, an exit code of zero indicates a successful completion.  Does this mean that the task REALLY completed successfully?  No.  It means that whatever was the last step of the task returned an exit code of 0 to whatever was watching it (i.e. the Configuration Manager client).  I have seen plenty of crappy vendor installation packages fail and return a zero code.  I've also seen respectable vendor packages do this (a major CAD vendor's network deployment which fails when trying to install .NET 4 and DirectX in the silent bundle, in a particular version of their product line, would return 0).  For most simple tasks (an individual msiexec or setup.exe operation) a zero exit code is fairly reliable, but as I always say: TEST, TEST, TEST, and then TEST AGAIN.

3010 - "a restart is required to complete the install"

This is similar to zero, except that it also indicates that a system restart is required in order to complete the task successfully.  If you are running multiple step tasks, and any one of the tasks returns a 3010 exit code, and you are suppressing restarts throughout, make SURE you execute a restart at the very end.  In addition, if you are using a product like Microsoft System Center Configuration Manager, you need to modify the Program to indicate that the program will restart the computer when finished running.  This is especially important if the program is a script.

1605 - "this action is only valid for products that are currently installed"

This exit code applies to uninstalls and indicates that the .MSI or GUID specified in your script to run as an uninstall (e.g. /x) is not actually installed.  It may also indicate a corrupted installation, whereby there are in fact bits of the product installed all over the place (files, folders, shortcuts, registry entries, DLL registrations, .NET assemblies, etc.) but the required references to tell Windows that the product is in fact installed are broken or missing.  If you are building this into your script, make sure that if you fire off an "msiexec /x blah-blah-blah" statement that returns 1605, to also follow behind that with additional checks for remaining pieces to clean-up.

1633 - "this installation package is not supported on this platform"

As you might have guessed, this means that an attempt was made to install an MSI package on a non-supported platform (i.e. operating system version or service pack level).

1632 - "the temp folder is either full or inaccessible"

I've seen this error when an overzealous sys-admin ran a scheduled task/script to clean out "temp" folders and also removed the temp folder itself.  I've also seen it (less often) when the security permissions on the temp folder are changed from their default configuration (whether it be the Windows\Temp folder, or the user's individual temp folder).

As a follow-up on 1605: if you are creating a script to run via Configuration Manager to uninstall an application, and you get this exit code, you might want to override the return value.  As an example, rather than raising the %errorlevel% value (option [1] below), return an explicit zero (option [2] below)...

[1] exit %errorlevel%

[2] exit 0

Someone asked me recently about why I would recommend this. It's simple: if you are deploying an advertised uninstall program, and it runs on a client that doesn't have the installed application, it may return 1605, which means "not installed, move along", which technically isn't a failure and should not return a "failed" result to Configuration Manager.  If it runs on a client where it isn't applicable, it should bail out and say it was successful, or you can use another explicit exit code and have a better/clearer picture of how many actually ran the uninstall.

1622 - "error opening installation log file"

If you like to use logging options with MSIEXEC, make sure the log output path is valid, and that the permissions allow for creating and updating the log file under the context by which the package is installed (or uninstalled).  This will often return a 1622 exit code.

1608 - "unknown property"

This exit code indicates an invalid property parameter was passed in the command line.  The most common cause of this is fat-fingering.  For example, when specifying "INSTALLLEVEL", but you leave out one of the "L" characters (e.g. "INSTALLEVEL") it will blow up with a 1608 exit code.

The single most important takeaway from this is that if you use scripts with deployment systems like Configuration Manager, you need to be careful to not only watch for exit codes, but watch for how you are raising the results up to the Configuration Manager agent.  In most cases, raising the explicit exit code is best, but there are times where you may want to override it (such as 1605).  Scripting is like a giant box of Lego(R) blocks, allowing you to build incredible things.  But you need to make sure the towers and bridges you build with them don't crash under their own weight.

1 comment:

skatterbrainz said...

I forgot to add a comment on 1603: which is that it is VERY often caused by running the task without sufficient permission. In other words, it was attempted by an account that did not have admin permissions to uninstall software. Not always, but very often this is the cause.