WiX MajorUpgrade of Windows Service, preserving .config, and avoiding a reboot
Asked Answered
O

2

11

I am struggling to get MajorUpgrade, ServiceControl, .config files to work nicely together. After my other question, I'm now kinda having the opposite problem again.

Before, the files weren't being overwritten because the AssemblyFileVersions were static so I fixed that. 1) Now, even with Schedule="afterInstallExecute" my KeyPath='yes' .config file is still being overwritten even though the existing file modified date is different than the file creation date and it is set as a KeyPath. I'm currently having to overwrite the .config file and restart the service after the install.

2) And even if I fix that, I still have a problem of avoiding a reboot. If I say Schedule="afterInstallInitialize" then I believe the .config file will certainly be removed along with the service too early. If I say Schedule="afterInstallExecute" then the service isn't stopped and after the install a reboot is necessary. (That's right, right?) Stopping the service manually prior to the install let's me avoid the reboot. Adding a net stop custom action could work to replace the ServiceControl I guess, but getting all the conditions right seems complex.

3) As a bonus, I'd like to NOT remove the service at all during an upgrade. Can I just stop the service, replace the binary, and start the service again? That will avoid re-entering the service account credentials for an upgrade. But of course it still needs to install on a first install and uninstall on a feature removal.

Here's the meat of it (which is also bundled later, in case that somehow matters):

<MajorUpgrade DowngradeErrorMessage="A newer version is already installed." 
              Schedule="afterInstallExecute" />

<ComponentGroup Id="ServiceCG">
    <Component Id="Service" Guid='*' Win64='yes' Directory='INSTALLDIR'>
        <File Id='ServiceEXE' Source='$(var.root)Service.exe' />
        <ServiceInstall Id="ServiceInstall"
                          Name="MyService"
                          DisplayName="My Server"
                          Type="ownProcess"
                          Start="auto"
                          ErrorControl="normal"
                          Description="My Server Service"
                          Interactive="no"
                          Account="[...]"
                          Password="[...]" />
        <ServiceControl Id="StopService" Name="MyService" Start="install" 
                        Stop="uninstall" Wait="yes" Remove="both" />
        <util:User Id="UpdateServiceAccountLogonAsService" UpdateIfExists="yes"
                   CreateUser="no" Name="[SERVICEACCOUNTFULL]" 
                   LogonAsService="yes"/>
    </Component>
    <Component Id="ServiceConfig" Guid='*' Win64='yes' Directory='INSTALLDIR'>
        <File Id='FileServiceConfig' KeyPath='yes' 
              Source='$(var.root)Service.exe.config' />
    </Component>
</ComponentGroup>

Related but unanswered:

WiX version 3.8.1128.0

Outlive answered 28/4, 2014 at 19:35 Comment(3)
Which version of wix are you using? Knowing that may help you get a useful answer.Nemesis
WiX version 3.8.1128.0Outlive
WiX version isn't really relevant to this question. All of the elements involved map to Windows Installer tables and no additional custom extensions. It's the underlying MSI behavior that is important.Bilingual
S
5

EDIT: it seems this explanation of the same issue, or on the same topic at least, might be easier to understand: Msiexec: automatic rollback to previous version on installation failure


You are banging your head against several core MSI usage problems here.

  1. File versioning: during installation the default file overwrite mode (defined by the REINSTALLMODE property) won't replace files that are equal version by default. This can be changed by setting REINSTALLMODE = "emus". This will replace files with equal version for versioned files. Unversioned files will be preserved if modify and create dates are different.
  2. Upgrade behavior: like Chris says, files that appear to be reverted to default are actually uninstalled and reinstalled due to major upgrade configuration. File preservation is only possible in major upgrades if RemoveExistingProducts is placed late in the InstallExecuteSequence. Then shared files between releases are never uninstalled and the file versioning rules described in point 1 apply for overwriting.
  3. Service configuration preservation: avoiding re-entry of service credential information is a common problem for major upgrades that uninstall early in the InstallExecuteSequence. In other words the product is uninstalled and then reinstalled wiping out changed files. I don't recommend it, but some people argue for this solution: How to only stop and not uninstall windows services when major upgrade in wix? (Rob Mensching is the WIX and Orca author - I think he is suggesting this solution as an option, and not necessarily a recommendation. Please ask in the linked post to be sure). With correct component referencing and uninstall placed late in the InstallExecuteSequence this problem is normally avoided altogether, and this is then a preferred approach (normal component referencing prevent the component from uninstalling altogether leaving service settings and changed config files intact - if, and only if, component referencing is correct - see description of this concept below). However, my preferred approach is still to use a separate MSI for the service install and configuration if you are using a user account to run the service - then it is a self contained deployment unit and can be included in a bootstrapper and updated on its own, and best of all: it is undisturbed by any other application changes or hotfixes. Finally I would like to point out that a service running with a user account isn't a recommended approach to begin with - for security and deployment reasons alike.

Component referencing: refers to the GUIDs assigned to MSI components and how they must match one, and only one (absolute) path at all times through all upgrades. See a better discussion of this with a couple of examples here: Change my component GUID in wix?

I didn't mention the option of setting the MSI components installing services to permanent to prevent their removal on uninstall for the simple reason that this isn't good practice at all. Then files and registration will remain on final uninstall, and you need a custom action to clean up. Very bad practice and bound to cause lots of extra work and problems with dangling component references.

Subsoil answered 8/5, 2014 at 16:43 Comment(6)
For 1, how are .config files versioned? I'm not convinced that overriding REINSTALLMODE is necessary. And how should ServiceControl be set along with <MajorUpgrade Schedule="afterInstallExecute" /> so that the reboot isn't required? With an upgrade, is the service stopped and then started once during the install and a second cycle during the uninstall? With <ServiceControl Start="both" Stop="both" Remove="both" /> and regardless of Wait= yes/no, the initial install is failing because the GAC'd assemblies are still in the GAC Temp directory when the service is started.Outlive
.config files aren't versioned. The replacement logic will not replace a modified file (create and modify dates are different). With regards to the GAC, read this please and really evaluate your priorities with regards to the GAC: #2451623Bologna
These assemblies are versioned over time and run side-by-side in isolated app domains.Outlive
I've asked the moderator to award at least 25 bounty points here. You put a lot of effort in here. Thanks. It a happened last minute and I was out.Outlive
Those component rules ... I don't believe I'm violating any of them there, right? One file per and I use * to auto-generate.Outlive
Here is a similar explanation, using a different focus: Msiexec: automatic rollback to previous version on installation failureBologna
B
4

The file create/mod rule only applies to install/reinstall a component. It doesn't prevent the component from being uninstalled. Your major upgrade is scheduled very early which means the previous version is completely uninstalled and then then the new version is installed. This is why your file is overwriting when you don't expect it to. Schedule RemoveExistingProducts later to avoid this problem.

Set your Stop attribute to both install and uninstall. Those two changes should solve your problems.

Bilingual answered 8/5, 2014 at 13:33 Comment(1)
How should ServiceControl be set along with <MajorUpgrade Schedule="afterInstallExecute" /> so that the reboot isn't required? With an upgrade, is the service stopped and then started once during the install and a second cycle during the uninstall? With <ServiceControl Start="both" Stop="both" Remove="both" /> and regardless of Wait= yes/no, the initial install is failing because the GAC'd assemblies are still in the GAC Temp directory when the service is started.Outlive

© 2022 - 2024 — McMap. All rights reserved.