Wix - ServiceControl 启动需要四分钟才能失败,应该是 30 秒

Wix - ServiceControl start takes four minutes to fail, should be 30 sec

我的服务在安装过程中自动启动...

<ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="HeskaGateway" Wait="yes" />

如果我为服务提供有效的连接字符串,它就可以正常工作。如果我提供了错误的连接字符串,服务将很快启动和停止……当我转到“服务”并进行手动启动时,我会看到这一点。根据 MSI ServiceControl Table 上的文档,"yes" 的等待值变为 1,这意味着它应该等待 30 秒然后失败。耗时 4 分 7 秒。为什么这么久?

MSI (s) (6C:78) [16:36:41:932]: Executing op: ServiceControl(,Name=HeskaGateway,Action=1,Wait=1,)
StartServices: Service: Heska Gateway
MSI (s) (6C:78) [16:40:48:862]: Note: 1: 2205 2:  3: Error 
MSI (s) (6C:78) [16:40:48:862]: Note: 1: 2228 2:  3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1920 
Error 1920. Service 'Heska Gateway' (HeskaGateway) failed to start.  Verify that you have sufficient privileges to start system services.

编辑:我从来没有弄清楚我真正的问题是什么。我还有一个安装顺序错误,因为我的 CustomAction(延迟)会在 ServiceStart 之后触发,它会编辑 JSON 文件中的连接字符串。在延迟的自定义操作之后尝试移动 ServiceStart 很糟糕。所以我从 ServiceControl 条目开始,然后添加了另一个自定义操作,它默默地 运行 "SC.EXE start HeskaGateway"。我将在下面记录下来作为解决方案。

错误 1920:此错误似乎表示缺少特权 (logon as a service) 或访问权限,或者可能来自外部原因或者MSI软件包的某种干扰不是运行宁提升(我认为不太可能 - 那么您只能写入每个用户路径)。

  • 您是否运行使用LocalSystem account or NetworkService or LocalService or with a regular user account? (about the above service accounts提供此服务)。
  • 或者managed service accounts, group managed service accounts or virtual accounts step-by-step info的新概念(我不太了解的概念)。
  • 如果您使用普通用户帐户,它是否具有“作为服务登录”权限集?
    • 如果您在 WiX MSI 中创建用户(或定义它),则可以为相关 User(元素)设置 LogonAsService="yes"。我相信这会增加帐户的权限 (SeServiceLogonRight)。
    • 特权不同于访问权限 (ACL) - 记录在案:特权是对某种功能/特性的普遍系统范围访问 - 例如更改系统时间、启动/停止服务、登录为服务等... ().
  • 你的测试盒上有安全软件/杀毒软件吗?它可能会干扰您设置的 API 调用。如果是这样,请尝试在安装过程中禁用它(如果可能)。我也会提到 防火墙
  • 你的 MSI 设置为 运行 提升 了吗? (Package Element => InstallPrivileges).
  • UPDATE:只是添加问题结果是:配置数据的自定义操作更新需要 运行 具有提升的权限 错误的服务配置数据 导致了一般的 1920 错误消息。在这种情况下,配置采用 JSON 格式,显然可以采用多种格式:XMLregistryINI 等......更多信息请参见上面的 OP 评论详情。

Timeout:关于长时间超时。我有时在 安全软件 中看到过这种情况(锁定整个设置,因此服务超时 运行s 仅在一些扫描延迟后),或者在触发创建 运行s 的设置中看到=43=]系统还原点 首先开始安装(这可能是某些 MSI 安装在通常快速完成时突然需要很长时间的可能原因之一 - 可以 prevent this restore point creation - MSIFASTINSTALL). Also, maybe check this answer from serverfault and the registry value described for whether there is a policy on your network to change the default service start timeout: How do I increase windows service startup timeout (ServicesPipeTimeout)。坦率地说,我不确定 MSI 使用自己的超时时间还是系统默认的超时时间 - 也许有人可以阐明?也可以推测 数据库连接 你启动有自己的超时?(与你的交互式测试体验不匹配?)也许你可以检查你的代码和你的电话,让我们知道?你的服务是否依赖于另一个服务?(请参阅下面的 symantec link)。安装到 GACWinSxS[ 的文件的任何 依赖项 =85=] 正如 Chris 在第一个 link 下面?

很多猜测。让我们希望其中的一些帮助或它激发了解决问题的其他想法。在一些 link 下方进行保管(尝试写一个通用的答案,也可以帮助其他人解决相同或相似的问题 - 这使得答案太长,对此感到抱歉)。


链接:

服务本身可能正在做某事。服务控制协议包括从服务本身返回的服务状态,它告诉 Windows 发生了什么。其中一项是等待提示。由于对该服务一无所知,该服务可能意识到它的启动速度可能很慢,并告诉 Windows(带有等待提示)它应该等待更长时间。 30 秒实际上是一个默认值,而不是一个固定值。此 post 指的是托管代码服务的等待提示:

How to choose value for serviceStatus.dwWaitHint?

您没有显示用于安装服务的 ServiceControl,但如果它与同一进程中的另一个服务共享,事情就会变得复杂,因为进程本身无法终止,同时它还托管另一个服务。

安装程序有一个自定义 UI,要求用户复制并粘贴支持部门提供给他们的连接字符串。安装程序使用延迟的 CustomAction 编辑应用程序文件夹中的 JSON 文件。它被推迟是因为它需要在文件写入磁盘之后进行,并且还需要具有提升的权限。这一切都很好,直到我决定让服务自行启动安装 "at the end"。我的第一次尝试是使用

<ServiceControl Id="StartService" Start="install" ...>

但这需要 4 分钟才能失败。故障排除显示服务在将连接字符串写入 JSON 文件的自定义操作之前启动。我需要将服务启动延迟到自定义操作之后。我考虑将第二个 ServiceControl 条目添加到它自己的组件中,该条目可以安排在很晚的时候,但这让我感到不舒服,因为我要中断卸载和修复安装。所以,我只是在 JSON 文件编辑之后添加了另一个延迟的自定义操作。 该新操作执行 "SC.EXE start MyServiceName"。 SC.EXE 是一种启动服务的非阻塞方式,无论成功或失败,它都会很快完成。

我的最终解决方案:

 <Component Id="MyCloudSync.exe" Guid="{generate-your-own-guid}">
    <File Id="MyCloudSync.exe.file" KeyPath="yes" Source="$(var.RELEASEBINARIES)\MyCloudSync.exe" />
    <ServiceInstall Id="MyCloudSync.exe"
          Type="ownProcess"
          Name="MyGateway"
          DisplayName="My Gateway"
          Description="Synchronizes laboratory data with Cloud"
          Start="auto"
          ErrorControl="normal" />
    <!--Start is performed by a customer action that calls SC.EXE so it can be delayed after the custom action that writes the JSON file -->
    <ServiceControl Id="StartService" Stop="both" Remove="uninstall" Name="MyGateway" Wait="yes" /> 
  </Component>

您应该注意上面的 ServiceControl 条目没有 "start=" GetConnectionString 和 SetConnectionString 调用的 DLL 是我自己制作的。 Wix 有自己的 运行 命令行自定义操作... WixQuietExec

 <CustomAction Id= "GetConnectionString"
                  BinaryKey="MyCustomActions"
                  DllEntry="GetConnectionString"
                  Execute="immediate"/>
    <CustomAction Id= "SetConnectionString"
                  BinaryKey="MyCustomActions"
                  Impersonate="no"
                  DllEntry="SetConnectionString"
                  Execute="deferred"/>
    <CustomAction Id="SetConnectionStringDeferredParams"
                  Property="SetConnectionString"
                  Value="&quot;[INSTALLFOLDER]&quot;&quot;[CONNECTIONSTRING]&quot;" />
    <Property Id="QtExecStartService" Value="&quot;SC.EXE&quot; start MyGateway"/>
    <CustomAction Id="QtExecStartService" 
                  BinaryKey="WixCA" 
                  DllEntry="WixQuietExec" 
                  Impersonate="no"
                  Execute="deferred" 
                  Return="ignore"/>

启动服务只是为了方便安装程序,以防止转到 Services.msc 执行启动或要求重新启动。所以我用了Return="ignore"。另外 SC.EXE 只是将服务放入 "Start Pending" 中,所以它可能不会 return 出现太多错误,除非您的服务不存在。

注意: WixQuietExec 已记录 here。确保引用 EXE 并为您的 属性 提供与使用 WixQuietExec 的 CustomAction 相同的 ID。该信息在 "Deferred Execution" 下,但我第一次尝试时仍然弄错了。