我们使用Wix安装我们的软件。我们的设置还安装了Windows服务。要允许用户更改Windows服务的登录信息,我们只想在首次安装时安装该服务,并仅在卸载时将其删除。对于升级,我们手动停止服务,以便升级文件。
我们有这个工作,但最近我们发现在某些机器上,在UnpublishFeatures期间卸载了Windows服务:
如果失败的升级日志:
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
这是来自成功升级的日志:
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上删除了该服务,因此它会尝试配置该服务,但由于不再安装该服务而失败:
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.
我的猜测是发生这种情况是因为组件的操作对于两次升级都是不同的,对于失败的升级,这些是组件操作:
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
对于成功升级,这些是组件操作:
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
正如您所看到的,升级失败的操作是“缺席”,而成功升级的操作是FileAbsent。从我读过的FileAbsent意味着重新安装该功能,Absent意味着该功能将被删除。
我的问题是如何确定组件的操作,以及为什么它在一台机器上缺席并在另一台机器上FileAbsent。有没有办法解决这个问题?
组件如果配置如下:
<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>
答案 0 :(得分:0)
空白组件GUID :Guid=""
这是您最近设置的内容吗?我相信,这将为组件设置一个空白的GUID,这意味着它将在第一次安装时安装,之后从未接触或升级(除非您在升级时找到了重新安装组件的技巧) - 并且它不会我记得,已经卸载了。
晚REP :以上(空白GUID)似乎不符合您的要求。您只是希望组件在主要升级时不卸载,在这种情况下,您通常会在RemoveExistingProducts
后面移动InstallExecuteSequence
- 这需要您遵循所有组件规则到字母。这是非常复杂的运行时行为,但是一个简单的概念。基本上,您的新版本将作为补丁安装 - 覆盖文件而不先卸载它们 - 允许保留您的服务凭据,因为托管该服务的组件永远不会被卸载。
早期REP :仅为了记录,进行重大升级的常用方法是在RemoveExistingProducts
的早期安排InstallExecuteSequence
卸载所有文件,然后重新安装。使用此方法是因为它允许草率组件引用。它是用于清除许可证密钥,服务凭证等用户数据的。
永久组件 :另一种方法是将托管组件设置为永久性。然后它将永远不会在主要升级期间卸载(即使您使用早期REP),但也不会在常规卸载期间卸载,因此在系统上搁置有问题的文件(除非您添加自己的自定义清理功能 - 这可能非常容易出错。)
自定义操作备份机制 :其他人依靠自己的自定义操作(example)来备份在升级过程中被清除的数据,然后重新应用升级完成后,他们。 我认为非常容易出错的方法。
仅限服务MSI :您还可以将服务安装放在自己的MSI中,以使其更新更易于控制 - 或者在主要设置不能的情况下要尊重组件规则。这也有点复杂,但比我视图中的自定义操作要好。
次要升级 :如果您可以使用次要升级来安装升级,则可以避免此服务凭据问题。我将链接到另一个描述此问题的答案:Restarting windows service during WIX upgrade。
(托管)服务帐户 :您可以使用没有(about service accounts)凭据的常规服务帐户来运行服务,例如{{3} },LocalService或LocalSystem(我认为这对你来说显然是不可能的)。或NetworkService,managed service accounts或虚拟帐户group managed service accounts的新概念(我对此不太了解的概念)。
其他方法 :毫无疑问,其他方法也是如此。我想您可以将服务配置保留在MSI之外并通过脚本应用它。我不推荐它。我知道有些人在使用服务和计划任务之间切换,具体取决于step-by-step info(如果是the nature of the task at hand,则基本上切换到计划任务)。虽然有风险,但我认为您可以将服务配置推迟到用户在安装后启动的高级EXE(显然用户必须是管理员),然后可以设置具有一定交互性的配置(错误和状态消息直接到用户 - 而不仅仅是隐藏在日志中)有时可以帮助人们前进。虽然不是我推荐的方法 - 提升动作是设置的目的。我喜欢在应用程序中执行的任何非提升配置。
常见的真实MSI问题 :我写了一篇关于MSI实际应用中出现的一些常见问题,这里是:{{3这不是很好。我对此并不是很满意 - 它缺乏多种方式 - 但它确实存在,以防它可以提供帮助。在可用的时间内尽力而为。请把它当作它的原因:未完成的现实问题转储,在这里和那里可以尝试解决问题。