Components uninstalled during major upgrade - iis

I have a WiX installer that supports major upgrades. I found that in some specific test environments, the installer on upgrade would remove existing unchanged components.
These (IIS web app pool, IIS website, etc.) components are installed in this way, under TARGETDIR:
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="myComponent" Guid="MY-GUID">
<iis:WebAppPool Id="ID" Name="MyWebAppPool" Identity="networkService" ManagedPipelineMode="classic" ManagedRuntimeVersion="v4.0"/>
</Component>
</Directory>
For the problem environments, the app pool is deleted on upgrade.
Upgrades are authored in this way:
<MajorUpgrade Schedule="afterInstallExecute" DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit." AllowDowngrades ="no" />
In upgrade logs, I see these entries:
MSI (s) (58:20) [11:22:58:433]: Allowing uninstallation of shared
component: {MY-GUID}. Other clients
exist, but installed to a different location
In environments where the problem is not seen (ie. the components are not uninstalled on upgrade), I see these log entries:
MSI12cb8.LOG:9594:MSI (s) (10:EC) [09:36:37:068]: Disallowing
uninstallation of component: {MY-GUID}
since another client exists
The only explanation I've been able to come up with is that for the problem environments, TARGETDIR changes between the initial install and the upgrade. According to Rob, TARGETDIR is set to the largest drive. If the largest drive (drive with most free space available?) on a system changes between initial install and upgrade, the keypath of the components will change causing the components to be uninstalled on upgrade.
Questions
Does this explanation sound correct?
How can I fix this for upgrades to existing product installations? Is there a way to set TARGETDIR on upgrade to the same value used for initial install?

What's happening appears to be this: Your upgrade installs to some TARGETDIR that you seem to be saying you have little control over. At the end of that upgrade, RemoveExistingProducts uninstalls the old product, and that includes removing the app pool because the component is being uninstalled, presumably with a custom action (because there is no native support for app pools). Removing the component from the old location is fine because it's no longer needed there, but it looks like the custom action that removes the app pool is tied to that component removal and therefore deletes the app pool. In other words you have tied your app pool to the component sharing rules that now require you to do an in-place upgrade. Another way of looking at it is that in situations like these people add a "AND NOT UPGRADINGPRODUCTCODE" to the uninstall condition on the CA that removes the app pool so that it doesn't delete the app pool on an upgrade because it may just have been created in a new location, as in your case.
That's rather long winded, sorry, but the requirement for an in-place upgrade is usually met by having something on the system that you can search for (such a registry entry) and set the install folder to that location, disallowing any UI that can change it. You should also start getting control over your install folders (you make it sound like your install could go literally anywhere). The key word here is "default". TARGETDIR will default somewhere if you can't be botherd to set it.

For anyone else who stumbles upon a similar problem, I worked around it using a custom action. As #PhilDW pointed out, NOT UGPRADINGPRODUCTCODE will not work for the existing install. I couldn't figure out a way to stop the app pool deletion on upgrade. Instead, I added a custom action scheduled for after removal that adds the app pool back, if it was deleted.
<CustomAction Id="CreateAppPoolCustomAction.SetProperty" Return="check" Property="CreateAppPoolCustomAction" Value="AppPoolName=$(var.AppPoolName)" />
<CustomAction Id="CreateAppPoolCustomAction" BinaryKey="MyCustomActions.CA.dll" DllEntry="CreateAppPoolCustomAction" Execute="deferred" Return="check" Impersonate="no" />
<InstallExecuteSequence>
<Custom Action="CreateAppPoolCustomAction.SetProperty" Before="CreateAppPoolCustomAction" />
<Custom Action="CreateAppPoolCustomAction" After="RemoveExistingProducts">WIX_UPGRADE_DETECTED AND NOT (REMOVE="ALL")</Custom>
</InstallExecuteSequence>
The C# custom action in MyCustomActions.dll usesMicrosoft.Web.Administration.ServerManager to create the application pool, if it's missing.

Related

Preventing a user from uninstalling the application based on registry search

I have created 3 independent MSI files using WIX3.8
The first MSI package is the core package which installs the basic(Core) components.
The other two MSI packages are add on to the first MSI. I have put the necessary checks in place which will prevent a user from installing the add-ons if the basic components are not installed.
The problem now is how do I prevent the user from un-installing the core components when the add-ons are installed?
I have added specific registry keys while installing each MSI so that I can refer them.
I have spent over 2 days on Google and SO but could not find any solution :(. If I missed anything please provide me the reference link.
Any help is greatly appreciated.
Use the Upgrade element with the other addon components upgrade codes to detect the other products.
E.G. In your core components installer add something like
<Upgrade Id ="Addon Product A's Upgrade GUID">
<UpgradeVersion OnlyDetect="yes" Minimum="0.0.0.0" Property="ADDONADETECTED" IncludeMinimum="no" />
</Upgrade>
<Upgrade Id ="Addon Product B's Upgrade GUID">
<UpgradeVersion OnlyDetect="yes" Minimum="0.0.0.0" Property="ADDONBDETECTED" IncludeMinimum="no" />
</Upgrade>
<Condition Message="There are other products that depend on these components, aborting uninstall.">
<![CDATA[ADDONADETECTED OR ADDONBDETECTED AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")]]>
</Condition>
I would:
Add ARPSYSTEMCOMPONENT to those MSI files so they don't show in Programs&Features.
Assuming you allow normal major upgrades, make the bundle do the uninstall with a command line parameter such as BUNDLEUNINSTALL=1 and then have a type 19 custom action that prevents the uninstall from continuing if REMOVE="ALL" AND BUNDLEUNINSTALL<>1.
I'm not sure that a registry search provides a good solution. I would use a custom action based on MsiEnumRelatedProducts (upgradecode of other products using these components) to find the ProductCodes of those products. If you get some ProductCodes back then you can call a type 19 custom action to prevent the uninstall. In general Rick's suggestion is good, but I think the strategy you should go for is to use a bundle. This kind of thing: http://wixtoolset.org/documentation/manual/v3/xsd/dependency/provides.html

WiX: Installer always changes AppPool to enable 32bit app

WiX installer installs silverlight web application. It can work under 32 or 64 bit app pool. But when installation completed I see that selected app pool always set to Enable 32-bit applications.It is even for 64-bit pools. It is not sutiable because it can change existing pool for previously installed 64 applications.
I do not change explicitely this parameter. What is the reason of problem may be?
The code sample added:
<Component Id="WebAppVDirComponent"
Guid="C7A4B0E8-2389-4A2A-B285-96960BEE1C52" KeyPath="yes">
<Condition><![CDATA[RBGROUP_HOSTING = "iis"]]></Condition>
<iis:WebVirtualDir Id="VDir"
Alias="[WEB_APP_NAME]"
Directory="INSTALLDIR"
WebSite="TheWebSite" >
<iis:MimeMap Id="SilverlightMimeType" Extension=".xap" Type="application/x-silverlight-app" />
<iis:WebApplication Id="WorkWebApplication"
Name="[WEB_APP_NAME]" WebAppPool="TheAppPool"/>
</iis:WebVirtualDir>
<iis:WebAppPool Id="TheAppPool" Name="[APP_POOL_NAME]" ></iis:WebAppPool>
<CreateFolder/>
</Component>
This had been designed in a very elegant way, in my opinion.
If you place the <iis:WebAppPool> element declaration to the <Component> marked as Win64="yes", the application pool will be created with Enable32bit flag set to false. Otherwise (that is, by default), it will be created with Enable32bit set to true.
I'm not sure how it will behave when you don't create the application pool with your installation, but reference the existing one instead. I would expect it not to change this flag at all. You can experiment with this to find out how it works exactly.
And a side note: I would avoid installing to the existing application pool or website. This is far more difficult to maintain - remember that you must leave the machine in its "pre-install" state after uninstallation. This means you'll have to maintain backup/restore the state of everything you change with custom actions... Brrr...

Display additional dialog when application is in upgrade mode

I created a setup file which is working awesome.
Now whenever I rebuild an application without changing anything but Package Code is changed and then while I am going to install this version then a dialog will come "Upgrade Dialog" which ask me for upgrade an application.
Now in this situation I want to display an additional dialog created by me.
I am using the Insatllshield 2012 BASIC MSI project type.
I solved this problem.
There are two properties exist in Installshield named "IS_MINOR_UPGRADE" and "IS_MAJOR_UPGRADE".
When there is a minor upgrade at that time IS_MINOR_UPGRADE will set to 1. And same for Major upgrade.
So using these properties, I can recognize the Upgrade mode.
Any time you change the package code but not the product code you are talking about a Minor Upgrade or possibly a Small Update if you don't change the ProductVersion. Either way, the only way to create a custom message like you ask is to write your own setup.exe / update.exe bootstrapper to detect the update scenario and display your confirmation UI.
There's nothing built into MSI or IS that allows you to easily change this.

Disable StartIIS7Configuration transaciton on Uninstallation of Wix installer

I am having a problem with a Wix installer, that covers three different feature sets (Client / Developer and Server).
When Client is selected the installer does not need to perform any of the actions with IIS that are defined in components that aren't included within this feature.
On Installation I don't get a problem, as I have added a Custom Action
<!-- Only perform the IIS Configuration if we have installed the Admin Application-->
<Custom Action="SkipIISCA" Before="InstallValidate">
<![CDATA[COMPONENT_TYPE = 2]]>
</Custom>
Which is only run when the "Client" component type is being installed. The custom action sets the SKIPCONFIGUREIIS property to 1
The problem occurs when either a Repair on an uninstall is executed on the installer. It appears that IIS Configuration is being attempted when the product is being uninstalled or repaired, and the custom action does not seem be run to disable this behaviour.
Is there a good way to set the SKIPCONFIGUREIIS setting on uninstallation / repair based on a Registry Setting ?
Thanks.
Some of the properties set during an installation are stored in the hidden windows directory, c:\windows\installer - one per installation. In the log of your uninstall/repair session, you can see that cached file opened up and properties being set for the new uninstall/repair session. (Alternatively, you can find this temp file from the uninstall/repair log, and open it with Orca. In Orca, under "Property", it will show the values of any install properties saved).
Based on the above description, I bet that the property that the custom action is being set is not stored, but that the value of COMPONENT_TYPE is available (The same input that was used to set SKIPCONFIGUREIIS in the custom action).
If so, then just make the IIS configuration action be based on these properties:
<Custom Action="Your_Configure_IIS_Action" Before="InstallFinalize">
(NOT SKIPCONFIGUREIIS ) OR (COMPONENT_TYPE = 2)</Custom>
If you don't want the ConfigureIIS to happen for any feature set during uninstall/repair, then just use these properties:
<Custom Action="Your_Configure_IIS_Action" Before="InstallFinalize">
(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")</Custom>
Another thing to think about is if the original installer was at one level - e.g. a client, and the uninstall/repair is being done by someone at the server level. The component_type of the original install is stored. In that case, you might consider adding a check on how the component_type is determined (thru a dialog or some other attribute) during the uninstall/repair.

Two almost identical WIX projects - one works fine, the other fails with security issue

I have WIX installers for two windows services. Both are installed using the same credentials, but one works while the other fails with the error "Service "PCP Event Processor-3.9.9.0-wix' (MyServiceExeName) could not be installed. Verify that you have sufficient privileges to install system services.". I use a common wxi file for both projects with the credentials to use, so it's not an account name or domain name typo AFAICS. The only substantial differences between the two services being installed are:
The failing project has a .licx file for the 3rd party component.
the failing project is a WinExe project. The successful install is an Exe (Console style app)
As far as I can see, there is no real difference (obviously GUIDs are different) between the wxs files for the two installers. The failing component has WIX installer code like this:
<Component Id="cmpMainExe" Guid="{EXCISED-FOR-CUT-N-PASTERS}">
<File Id="filASJHDJSDJSHGDJH" Source="$(var.EventPollingService.TargetDir)\EventPollingService.exe" />
<ServiceInstall Name="$(var.SVCNAME)-$(var.ProductVersion)-$(var.BranchName)"
DisplayName="PCP $(var.SVCNAME)-$(var.ProductVersion)-$(var.BranchName)"
Type="ownProcess"
Interactive="no"
Start="auto"
Vital="yes"
ErrorControl="normal"
Description="Manages the state model of a user's session by handling incoming events from the dialler"
Account="$(var.ServiceAccountId)"
Password="$(var.ServiceAccountPwd)" />
<ServiceControl Id="StartWixServiceInstaller"
Name="$(var.SVCNAME)-$(var.ProductVersion)-$(var.BranchName)"
Start="install"
Wait="yes" />
<ServiceControl Id="StopWixServiceInstaller"
Name="$(var.SVCNAME)-$(var.ProductVersion)-$(var.BranchName)"
Stop="both" Wait="yes"
Remove="uninstall" />
</Component>
I'm using Wix 3.5 with Votive in VS 2010, and both projects are .NET 3.5 SP1 apps. I'm using Windows 7, with UAC turned off.
Any ideas?
Look at the two build MSI's in ORCA from Windows SDK and verify the ServiceInstall table entries look the same.
However, in my experience, this is not likely to be an installer issue. This is usually a red herring that points to an application problem such as missing dependencies or application exception. After you rule out the ServiceInstall entries and verify that the service account credentials are correct, the account is not disabled and the account has the authority to logon as a service then start profiling your application. This is easiest to do right when the installer is hung at the error window.
Two last thoughts:
If a program has dependencies on the winsxs or GAC it won't work as these don't get installed until Commit execution which is after trying to start the service
If you need to grant the user LogonAsService rights look at the User element in WiX.

Resources