Stop AppPool before installing website with WiX

3

I am trying to take an existing MSI that installs a website and add in the process of stopping the AppPool so that when installing an update you don't have to remember to stop the AppPool before running the installer.

The custom actions I've set up are listed below

<CustomAction Id='StopIisAppPoolCMD'
          Property='StopIisAppPool'
          Value='"[WindowsFolder]SysNative\inetsrv\appcmd.exe" stop apppool /apppool.name:"[WEB_APP_POOL_NAME]"'
          Execute='immediate' />
<CustomAction Id='StopIisAppPool'
          BinaryKey='WixCA'
          DllEntry='CAQuietExec64'
          Execute='immediate'
          Return='check' />

And they are scheduled in the msi product like this:

<InstallExecuteSequence>
  ...
  <Custom Action="StopIisAppPool" Before="InstallValidate"></Custom>
  <Custom Action="StopIisAppPoolCMD" Before="StopIisAppPool"></Custom>
  ...
</InstallExecuteSequence>

And the msi is wrapped in a bundle like this:

<Chain>
  ...
  <MsiPackage Name="MySetup.msi" DisplayInternalUI="yes"/>
</Chain>

When the custom actions are executed I'm getting this in the msi log

MSI (s) (94:A8) [14:43:48:833]: Doing action: StopIisAppPoolCMD

Action 14:43:48: StopIisAppPoolCMD.

Action start 14:43:48: StopIisAppPoolCMD.

MSI (s) (94:A8) [14:43:48:834]: PROPERTY CHANGE: Adding StopIisAppPool property. Its value is '"C:\WINDOWS\SysNative\inetsrv\appcmd.exe" stop apppool /apppool.name:"MyWebAppPool"'.

Action ended 14:43:48: StopIisAppPoolCMD. Return value 1.

MSI (s) (94:A8) [14:43:48:834]: Doing action: StopIisAppPool

Action 14:43:48: StopIisAppPool.

Action start 14:43:48: StopIisAppPool.

MSI (s) (94:2C) [14:43:48:837]: Invoking remote custom action. DLL: C:\WINDOWS\Installer\MSI2B0E.tmp, Entrypoint: CAQuietExec64

CAQuietExec64: Error 0x80070057: failed to get command line data

CAQuietExec64: Error 0x80070057: failed to get Command Line

CustomAction StopIisAppPool returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)

Action ended 14:43:48: StopIisAppPool. Return value 3.

Action ended 14:43:48: INSTALL. Return value 3.

I feel like my problems are possibly because I'm trying to do Execute='immediate' instead of deferred, but if I run the custom action as deferred, then it has to run after InstallInitialize which is too late to be stopping the AppPool to avoid file in use conflicts.

I was thinking it would be possible to run as immediate because the msi is wrapped in a WiX bundle, so I assumed it would be running with elevated rights before InstallInitialize since I have to put in an Admin password before the msi installer even starts.

I've considered putting these actions in a separate msi or exe package in the bundle and running it before the msi that installs the web files, but I would really rather not since the web app pool name is retrieved from the UI that already exists for the msi and if I can avoid it I would prefer to not have to redo how the UI is handled.

Is there a simpler way of going about this? am I missing something simple? or do I really need to redo the UI and split these actions into a separate exe package or msi inside of the bundle? If that's the case I may just say forget it and just make sure everyone knows to manually stop the App Pool before installing any new versions.

iis
wix
custom-action
wix3.9
asked on Stack Overflow Jan 10, 2017 by TJ Rockefeller

2 Answers

0

I have never had to stop the app pool before installing. ASP.NET runs out of a temporary directory and doesn't present any file lock issues. Also IIS automatically recycles the application pool when the web.config gets touched so all of this should be a total non issue.

answered on Stack Overflow Jan 11, 2017 by Christopher Painter
0

As per the WiX documentation page Quiet Execution Custom Action (underneath the "Immediate execution" heading), if your QuietExec custom action is set to Execute="immediate", you need to set a property called QtExecCmdLine when using CAQuietExec or WixQuietExecCmdLine when using WixQuietExec (instead of setting a property whose name is the ID of the custom action; that method is used when your custom action is deferred, only).

This is the code that worked for me (they recommend you use the newer WixQuietExec rather than CAQuietExec):

<CustomAction Id="StopApplicationPool_Cmd" Property="WixQuietExecCmdLine" Value="&quot;[SystemFolder]inetsrv\appcmd&quot; stop apppool MyApp" Execute="immediate" />
<CustomAction Id="StopApplicationPool" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="check" Impersonate="no" />
<CustomAction Id="StartApplicationPool_Cmd" Property="WixQuietExecCmdLine" Value="&quot;[SystemFolder]inetsrv\appcmd&quot; start apppool MyApp" Execute="immediate" />
<CustomAction Id="StartApplicationPool" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="check" Impersonate="no" />

Scheduled like this:

<InstallExecuteSequence>
...
  <Custom Action="StopApplicationPool_Cmd" Before="StopApplicationPool"><![CDATA[REMOVE OR UPGRADEFOUND OR UPGRADINGPRODUCTCODE OR REINSTALL]]></Custom>
  <Custom Action="StopApplicationPool" Before="InstallValidate"><![CDATA[REMOVE OR UPGRADEFOUND OR UPGRADINGPRODUCTCODE OR REINSTALL]]></Custom>
...
  <Custom Action="StartApplicationPool_Cmd" After="InstallFinalize"><![CDATA[UPGRADEFOUND OR UPGRADINGPRODUCTCODE OR REINSTALL]]></Custom>
  <Custom Action="StartApplicationPool" After="StartApplicationPool_Cmd"><![CDATA[UPGRADEFOUND OR UPGRADINGPRODUCTCODE OR REINSTALL]]></Custom>

...
</InstallExecuteSequence>
answered on Stack Overflow Jul 24, 2019 by bgh

User contributions licensed under CC BY-SA 3.0