Wix:升级时有时会卸载 Windows 服务 [英] Wix: Windows Service sometimes uninstalled when upgrading

查看:59
本文介绍了Wix:升级时有时会卸载 Windows 服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们使用 Wix 安装我们的软件.我们的设置还安装了 Windows 服务.为了允许用户更改 Windows 服务的登录信息,我们只想在第一次安装时安装该服务,并仅在卸载时将其删除.对于升级,我们手动停止服务,以便可以升级文件.

We install our software with Wix. Our setup also installs a Windows service. To allow users to change the login information for the Windows service we only want to install the service on first installation and only delete it on uninstall. For upgrades we manually stop the service so the files can be upgraded.

我们有这个工作,但最近我们发现在某些机器上 Windows 服务在 UnpublishFeatures 期间被卸载:

We have this working, but recently we found that on some machines the Windows service gets uninstalled during UnpublishFeatures:

如果来自失败的升级日志:

This if from a failed upgrade log:

Action 13:41:38: UnpublishFeatures. Unpublishing Product Features
MSI (s) (D8:EC) [13:41:38:346]: Executing op: FeatureUnpublish(Feature=Main,,Absent=2,Component=
UnpublishFeatures: Feature: Main
MSI (s) (D8:EC) [13:41:38:346]: Note: 1: 1402 2: UNKNOWN\Installer\Features\84B659030632F794E93A7CB19A87DB8E 3: 2 
MSI (s) (D8:EC) [13:41:38:346]: Executing op: ActionStart(Name=StopServices,Description=Stopping services,Template=Service: [1])
Action 13:41:38: StopServices. Stopping services
MSI (s) (D8:EC) [13:41:38:362]: Executing op: ProgressTotal(Total=1,Type=1,ByteEquivalent=1300000)
MSI (s) (D8:EC) [13:41:38:362]: Executing op: ServiceControl(,Name=RidderIQWebApi,Action=2,Wait=1,)
StopServices: Service: Ridder iQ Web API
MSI (s) (D8:EC) [13:41:38:393]: Executing op: ActionStart(Name=DeleteServices,Description=Deleting services,Template=Service: [1])
Action 13:41:38: DeleteServices. Deleting services
MSI (s) (D8:EC) [13:41:38:393]: Executing op: ProgressTotal(Total=1,Type=1,ByteEquivalent=1300000)
MSI (s) (D8:EC) [13:41:38:393]: Executing op: ServiceControl(,Name=RidderIQWebApi,Action=8,Wait=1,)
DeleteServices: Service: Ridder iQ Web API

如果来自成功升级的日志:

This if from a log from a successfull upgrade:

Action 11:53:24: UnpublishFeatures. Unpublishing Product Features
MSI (s) (CC:3C) [11:53:24:976]: Executing op: FeatureUnpublish(Feature=Main,,Absent=2,Component=
UnpublishFeatures: Feature: Main
MSI (s) (CC:3C) [11:53:24:977]: Note: 1: 1402 2: UNKNOWN\Installer\Features\84B659030632F794E93A7CB19A87DB8E 3: 2 
MSI (s) (CC:3C) [11:53:24:978]: Executing op: ActionStart(Name=RemoveFiles,Description=Removing files,Template=File: [1], Directory: [9])
Action 11:53:24: RemoveFiles. Removing files

如您所见,Windows Installer 会跳过 StopServices/DeleteServices 操作并开始删除文件.因为在安装过程中稍后在 UnpublishFeatures 上删除了该服务,它会尝试配置该服务,但由于不再安装而失败:

As you can see Windows Installer skips the StopServices/DeleteServices actions and starts removing the files. Because the service is deleted on UnpublishFeatures later during the setup it attempts to configure the service, but fails because it's no longer installed:

MSI (s) (D8:68) [13:42:34:772]: Executing op: CustomActionSchedule(Action=ExecServiceConfig,ActionType=3073,Source=BinaryData,Target=ExecServiceConfig,CustomActionData=)
MSI (s) (D8:90) [13:42:34:772]: Invoking remote custom action. DLL: C:\Windows\Installer\MSI170B.tmp, Entrypoint: ExecServiceConfig
ExecServiceConfig:  Error 0x80070424: Service 'RidderIQWebApi' does not exist on this system.
ExecServiceConfig:  Error 0x80070424: Failed to get service: RidderIQWebApi
CustomAction ExecServiceConfig returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
Action ended 13:42:35: InstallFinalize. Return value 3.

我的猜测是发生这种情况是因为两次升级的组件操作不同,对于失败的升级,这些是组件操作:

My guess is that this happens because the action for the component is different for both upgrades, for the failed upgrade these are the component actions:

MSI (s) (D8:68) [13:41:26:400]: Component: cmp.SR.SDKWebAPI.Service.exe; Installed: Absent;   Request: Local;   Action: Local
MSI (s) (D8:EC) [13:41:36:400]: Component: cmp.SR.SDKWebAPI.Service.exe; Installed: Local;   Request: Absent;   Action: Absent

为了成功升级,这些是组件操作:

For the successfull upgrade these are the component actions:

MSI (s) (CC:44) [11:53:17:386]: Component: cmp.SR.SDKWebAPI.Service.exe; Installed: Absent;   Request: Local;   Action: Local
MSI (s) (CC:3C) [11:53:22:850]: Component: cmp.SR.SDKWebAPI.Service.exe; Installed: Local;   Request: Absent;   Action: FileAbsent

如您所见,升级失败的操作为 Absent,升级成功的操作为 FileAbsent.从我读到的 FileAbsent 表示该功能已重新安装,而 Absent 表示该功能将被删除.

As you can see the action for the failed upgrade is Absent, and for the successfull upgrade is FileAbsent. From what I've read the FileAbsent means that the feature is reinstalled and Absent means the feature will be removed.

我的问题是组件的操作是如何确定的,为什么在一台机器上没有,而在另一台机器上有 FileAbsent.有没有办法解决这个问题?

My question is how are the actions for components determined, and why is it on one machine Absent and on another machine FileAbsent. And is there a way to fix this?

组件如果这样配置:

  <Component Id="cmp.SR.SDKWebAPI.Service.exe" Guid="">
    <File Id="fil.SDKWebAPI.Service.exe" Source="SDKWebAPI.Service.exe" KeyPath="yes" />
    <File Id="fil.SDKWebAPI.Service.exe.config" Source="SDKWebAPI.Service.exe.config" KeyPath="no" />
    <ServiceInstall Id="SDKWebAPI.Service.exe.Installer"
                    Type="ownProcess"
                    Name="RidderIQWebApi"
                    DisplayName="Ridder iQ Web API"
                    Description="Ridder iQ Web API service"
                    Start="auto"
                    Account="LocalSystem"
                    ErrorControl="ignore">
      <util:ServiceConfig FirstFailureActionType="restart" 
                          SecondFailureActionType="restart"
                          ThirdFailureActionType="restart"
                          RestartServiceDelayInSeconds="60" 
                          ResetPeriodInDays="0" />
    </ServiceInstall>
  </Component>

推荐答案

Blank Component GUID: Guid="" is this thing you最近定的?我相信,这将为组件设置一个空白的 GUID,这意味着它将在第一次安装时安装,之后再也不会接触或升级(除非您找到了一些在升级时重新安装组件的技巧) - 它不会据我所知,卸载了.

Blank Component GUID: Guid="" is this something you set recently? This will, I believe, set a blank GUID for the component, meaning that it will be installed on first install and never touched or upgraded afterwards (unless you have found some trick to reinstall the component on upgrade) - and it won't be uninstalled either as far as I recall.

Late REP:上述(空白 GUID)似乎与您的意图不符.您只希望组件在主要升级时不卸载,在这种情况下,您通常会在 InstallExecuteSequence 的后期移动 RemoveExistingProducts - 这需要您遵循所有组件规则一应俱全.这是一个非常复杂的运行时行为,但却是一个简单的概念.基本上,您的新版本将作为补丁安装 - 覆盖文件而不先卸载它们 - 允许保留您的服务凭据,因为永远不会卸载托管服务的组件.

Late REP: The above (blank GUID) does not seem like what you intend. You just want the component to not uninstall on major upgrade, in which case what you generally would do would be to move RemoveExistingProducts late in the InstallExecuteSequence - something which requires you to follow all component rules to the letter. This is very complicated runtime behavior, but a simple concept. Essentially your new version will install as a patch - overwriting files without uninstalling them first - allowing your service credentials to be preserved since the component hosting the service is never uninstalled.

早期 REP:只是为了记录,进行重大升级的常用方法是在 InstallExecuteSequence 的早期安排 RemoveExistingProducts 表示卸载所有文件,然后重新安装.使用这种方法是因为它允许草率的组件引用.它因清除许可证密钥、服务凭据等用户数据而闻名...

Early REP: Just for the record, the common way to do major upgrades is to schedule RemoveExistingProducts early in the InstallExecuteSequence meaning that all files are uninstalled, and then reinstalled. This approach is used because it allows sloppy component referencing. It is reknown for wiping out user data such as license keys, service credentials, etc...

永久组件:另一种方法是将托管组件设置为永久组件.然后它将永远不会在重大升级期间卸载(即使您使用早期 REP),但也不会在常规卸载期间卸载,因此将相关文件搁浅在系统上(除非您添加自己的自定义清理功能 -这很容易出错).

Permanent Component: Another approach would be to set the hosting component to be permanent. Then it will never be uninstalled during a major upgrade (even if you user early REP), but not during a regular uninstall either, hence stranding the file(s) in question on the system (unless you add your own, custom cleanup features - which can be very error-prone).

自定义操作备份机制:其他人依赖于自己的自定义操作 (example) 来备份在升级过程中被清除的数据,然后在升级完成后重新应用它们.在我看来非常容易出错的方法.

Custom Action Backup Mechanism: Others rely on their own custom actions (example) to back up the data that gets wiped out during upgrade and then reapply them after the upgrade is complete. A very error-prone approach in my view.

Service Only MSI:您还可以将服务安装放在自己的 MSI 中,以便您更容易控制其更新 - 或者在主设置无法控制的情况下遵守组件规则.这也有点复杂,但在我看来比自定义操作要好.

Service Only MSI: You can also put the service installation in its own MSI to make its update more controllable for you - or in case the main setup can't be made to respect the component rules. This is also somewhat complicated, but better than custom actions in my view.

次要升级:如果您可以使用次要升级来安装升级,则可以避免此服务凭据问题.我将链接到另一个描述此问题的答案:在 WIX 期间重新启动 Windows 服务升级.

(托管)服务帐户:您可以使用常规服务帐户,而无需 (关于服务帐户) 运行服务的凭据 - 例如 LocalService, LocalSystem网络服务(我认为这显然对你来说是不可能的).或者 托管服务帐户的新概念组托管服务帐户 或虚拟帐户 分步信息(我不太了解的概念).

(Managed) Service Accounts: You could use a regular service account without (about service accounts) credentials to run the service - such as LocalService, LocalSystem or NetworkService (which obviously is not possible for you I would presume). Or the newer concepts of managed service accounts, group managed service accounts or virtual accounts step-by-step info (concepts that I do not know enough about).

其他方法:毫无疑问还有其他方法.我想您可以将服务配置保留在 MSI 之外并通过脚本应用它.我不会推荐它.我知道有些人会根据 手头任务的性质(如果是任务,基本上切换到计划任务只偶尔运行一次).虽然有风险,但我想您可以将服务配置推迟到用户在安装后启动的提升的 EXE(在这种情况下,显然用户必须是管理员),然后可以设置具有一些交互性的配置(错误和状态消息直接到用户 - 而不仅仅是隐藏在日志中)有时可以帮助人们前进.虽然不是我推荐的方法 - 提升操作是设置的目的.我喜欢在应用程序中进行的任何非提升配置.

Other Approaches: There are no doubt other approaches as well. I suppose you could keep the service configuration out of the MSI and apply it via a script. I wouldn't recommend it. I know that some people toggle between using services and scheduled tasks depending on the nature of the task at hand (essentially switching to scheduled tasks if it is a task that runs only once in a while). Though risky, I suppose you could postpone the service configuration to an elevated EXE that the user launches after installation (the user must be admin in this case, obviously) which could then set up the config with some interactivity (error and status messages directly to the user - and not just hidden in logs) which can sometimes help to get people going. Not my recommended approach though - elevated actions is what a setup is for. Any non-elevated configuration I like to do in the application.

现实世界中常见的 MSI 问题:我写了一些在 MSI 实际应用中看到的常见问题,这里是:如何避免常见我的 WiX/MSI 部署解决方案存在设计缺陷? 这不是很好.我对它不是很满意 - 它缺乏的方式不止一种 - 但它就在那里,以防万一它可以提供帮助.这是在可用时间内的最大努力.请认清它的本质:现实世界问题的未完成转储,并在这里和那里提供一些您可以尝试解决问题的方法.

Common Real-World MSI Problems: I wrote about some of the common problems seen in practical application of MSI a while back, and here it is: How do I avoid common design flaws in my WiX / MSI deployment solution? It is not great. I am not very happy with it - it is lacking in more ways than one - but there it is, in case it can help. It was best effort in the time available. Please take it for what it is: an unfinished dump of real-world problems with a few pointers here and there for what you can try to deal with the problem.

链接:

这篇关于Wix:升级时有时会卸载 Windows 服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆