Tuesday, March 27, 2012

How to install msi package using ant


Problem:
to install msi package in silent mode using ANT.

Constraints:
1. some prodcuts require system rebooting after installer finishes working. That is represented in some exit code (or a set of possible codes) meaning approximately the following: "It is all okay but still user actions required". So you never get 0 exit code meaning regulary success operation completion.
2. sometimes we need not just click Next> while installing the package but rather specify some custom specifications on installation phase. This is sure our case :) Assume we need to override some public property of msi package. Let it be named SOMEPROPERTY and the value we'd like to assign is SOMEVALUE

Solution:
Actually several solutions could be applied to solve this problem. The simplest one is to set failonerror attribute of ant execute task to false. Such the solution has quite big and quite obviouse disadvantage: your automated procedure will never know any problem has happened. But we would actually like to skip the only one exit code to consider it successfull.
To achieve that we should approach with batch scripting (remember we're acting under windows as we're trying to imstall msi package which is true windows stuff)

so lets introduce the following batch script

msiexec /i %1 /qn SOMEPROPERTY=%2

IF ERRORLEVEL 1642 GOTO ERR

IF ERRORLEVEL 1641 GOTO 1641

IF ERRORLEVEL 1 GOTO ERR


:1641
ECHO.Returned expected error code. System is getting to be rebooted...
EXIT 0

:ERR
ECHO.Uexpected error code: %ERRORLEVEL%
ECHO.failing..
EXIT %ERRORLEVEL%

So, what we expect from this script? First of all we expect it to install the package we propagate via script argument %1 and set the property SOMEPROPERTY to the value we specify in script argument %2. However we would like our script behave in certain way to address the constraint #1 (see above)

In the script we call msiexec tool with the keys /i (install the package) and /qn meaning silent non-gui installation. The lines below address the problem of exit codes. We should catch the code meaning "Its okay but the system's going to be rebooted now". This is encoded with the exit code sequence 1641. However the called process may return some other code which we should consider as not successful. This is achieved by "IF ERRORLEVEL" and "GOTO" batch language construction.

IF ERRORLEVEL N returns true if the returned exit code equals or grated than N. That is why we try to catch all errors higher than N (=1641)


IF ERRORLEVEL 1642 GOTO ERR


... and all errors lower than N

IF ERRORLEVEL 1 GOTO ERR
The order of instructions invocation makes us sure we'll get to :1641 label if only the expected installation state will take place
So now we just should call the batch from ANT passing the corresponding cmd arguments like this:
<exec executable="install-msi.bat" failonerror="true" >
 <arg value="&quot;PACKAGETOINSTALL.msi&quot;"/>
 <arg value="&quot;SOMEVALUE&quot;"/>
</exec>