使用Windows服务更新软件包会重置服务的帐户和密码

Eur*_*lli 6 wix

我正在使用WiX处理MSI安装程序.我试图尽可能简化开发:这是一个内部产品,我的用户就是我们的IT人员.

该产品包括一个Windows服务,必须配置为在每台计算机的不同帐户下运行.

我为我的用户规划的工作流程(首次安装)如下:

  1. 运行安装程序(安装程序在默认帐户下设置服务)
  2. 通过sc或本地服务小程序停止服务
  3. 更新服务属性以在正确的计算机专用帐户下运行.(每台计算机的帐户不同,只有IT人员才能访问密码.)
  4. 重启服务

后续更新将包括从更新的MSI文件安装.

测试"小"更新时,我惊讶地发现安装程序将服务重置为在默认帐户下运行.这对我来说是一个主要问题,因为它使我的用户很难更新他们的服务器.每次有更新时,他们都必须在每台机器上重新输入帐户信息.我预计会发生"重大"更新,但不是"小"更新.

  1. 有没有办法配置安装程序,以便它不会在"小"或"次要"更新期间更改服务的现有帐户/密码配置?

  2. 这也会在"修复"过程中发生(我还没试过)?

这是我的组件在.wxs文件中的样子:

<Component Id="cmpService" Guid="{MYGUIDHERE}">
  <File Id="filService" KeyPath="yes" Name="ServiceApp.exe" />
  <ServiceInstall Id="ServiceInstall" Name="ServiceApp" DisplayName="My Service"
                  Type="ownProcess" Start="auto" ErrorControl="normal"
                  Account="LocalSystem">
    <util:PermissionEx ... attributes here... />
  </ServiceInstall>
  <ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall"
                  Name="ServiceApp" Wait="yes" />
</Component>
Run Code Online (Sandbox Code Playgroud)

Remove="uninstall"如果没有任何变化,我原本预计会保留服务.显然不是.(如果在"主要"更新中发生这种情况,我不会太担心).

我还注意到ServiceConfig元素的属性(OnReinstall)似乎符合条件,但基于蜡烛错误消息,很明显,它OnReinstall只是为了影响元素的配置成员(PreShutdownDelay等等)而不是服务安装.整个.

我调查过这些:

奇怪的是,这个答案表明这只是"主要"升级的问题.那不是我的经历.我的经历是侥幸吗?

在安装过程中提示输入帐户和密码会很好,但是在这种情况下将密码存储在注册表或其他地方并不是一个真正的选择,并且必须在每次更新时重新输入凭据就像必须重新配置一样具有破坏性.手工服务.

Dai*_*Dai 1

今天我就这个具体问题与 FireGiant 进行了电话咨询,我们找到了解决方案。

背景故事:

  • 我们的应用程序安装 MSILocalService最初使用 Windows 服务安装,但我们的实际桌面软件将其更改为NetworkService自定义用户帐户,这在某些网络环境中可能是必需的。
  • 我们的<Component> <ServiceInstall>元素Account="NT AUTHORITY\LocalService"看起来像这样:

    <Component Id="Comp_File_OurServiceExe" Guid="*">
    
        <File Source="$(var.TargetDir)OurService.exe" id="File_OurServiceExe" KeyPath="yes" />
    
        <ServiceInstall
            Id           = "ServiceInstall_OurServiceExe"
            Vital        = "yes"
    
            Name         = "RussianSpyingService"
            DisplayName  = "Russian Spying Service"
            Description  = "Crawls your network for incriminating files to send to the FSB"
            Account      = "NT AUTHORITY\LocalService"
            Type         = "ownProcess"
            Arguments    = "-mode service"
            Interactive  = "no"
            Start        = "auto"
            ErrorControl = "normal"
        >
    
            <ServiceConfig DelayedAutoStart="yes" OnInstall="yes" OnUninstall="no"  OnReinstall="yes" />
            <util:ServiceConfig FirstFailureActionType="restart" SecondFailureActionType="restart" ThirdFailureActionType="none" ResetPeriodInDays="1" />
        </ServiceInstall>
    </Component>
    
    Run Code Online (Sandbox Code Playgroud)
  • 当遵循这些重现步骤时,服务注册/配置将被无意重置:

    1. 使用 MSI 版本 1.0.0 完成安装
    2. 打开Services.msc并更改RussianSpyingService为使用NT AUTHORITY\NetworkService(而不是NT AUTHORITY\LocalService
    3. 使用相同的*.wxs文件创建一个新的 MSI,但文件版本更高,并为其提供更高的版本,例如 1.0.1(不要忘记 MSI 仅使用版本号的前 3 个组成部分并忽略第 4 个版本)
    4. 安装完成后,观察是否RussianSpyingService已重置为可以使用NT AUTHORITY\LocalService

顺便说一句,我问 FireGiant(他们的顾问以前在 Microsoft 工作,帮助公司的其他团队使用 MSI),哪些其他软件(例如 SQL Server)能够使用 MSI 来安装 Windows 服务,尽管升级安装之间的配置发生了变化,但这些服务仍能正常工作。他们告诉我,像 SQL Server 这样的产品经常使用自定义操作进行 Windows 服务配置,尽管一般建议避免使用自定义操作,但这是可以接受的,因为 Microsoft 的 SQL Server 团队足够大,可以投入工程和测试资源来确保它们正常工作。

解决方案

  • 简而言之:“使用 MSI 属性!”
  • 具体来说,定义一个表示Account属性值的 MSI 属性,并在 MSI 启动期间从注册表加载该值,如果该值不存在,则使用默认值NT AUTHORITY\LocalService
  • 理想情况下,属性值将存储在应用程序自己的注册表项中,并且应用程序有责任确保该值与当前服务配置匹配。
    • 这可以通过创建一个新的注册表项来完成,HKLMLocalServiceNetworkService(或任何服务帐户)写入它,因此当服务启动时,它会在那里记录其用户帐户的名称 - 但这很复杂。
    • 不要用于HKCU存储该值,因为这不起作用:HKCU针对不同的用户解析为完全不同的注册表配置单元(甚至可能无法加载或访问)。
  • 从技术上讲,另一个选项不受 Microsoft 支持,因为它使用 Windows 注册表自己的services注册密钥原始ObjectName(帐户名称)值 - 该值恰好与属性使用的格式相同AccountName=""。这也是最务实的,如下所述:

以下是对我们有用的方法:

  1. 在您的<Wix> ... <Product>...元素中,添加此<Property>声明和<RegistrySearch />元素:

    <?xml version="1.0" encoding="UTF-8"?>
    <Wix
        xmlns       = "http://schemas.microsoft.com/wix/2006/wi"
        xmlns:netfx = "http://schemas.microsoft.com/wix/NetFxExtension"
        xmlns:util  = "http://schemas.microsoft.com/wix/UtilExtension"
    >
    
        <Product
            Id="*"
            UpgradeCode="{your_const_GUID}"
            otherAttributes="goHere"
        >
    
            <!-- [...] -->
    
            <Property Id="SERVICE_ACCOUNT_NAME" Value="NT AUTHORITY\LocalService">
                <!-- Properties used in <RegistrySearch /> must be public (ALL_UPPERCASE), not private (AT_LEAST_1_lowercase_CHARACTER) -->
                <RegistrySearch Id="DetermineExistingServiceAccountName" Type="raw" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\RussianSpyingService" Name="ObjectName" />
            </Property>
    
            <!-- [...] -->
    
        </Product>
    </Wix>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 更新您的<ServiceInstall元素以使用新的SERVICE_ACCOUNT_NAMEMSI 属性而Account=""不是以前的硬编码NT AUTHORITY\LocalService

    <ServiceInstall
        Id           = "ServiceInstall_OurServiceExe"
        Vital        = "yes"
    
        Name         = "RussianSpyingService"
        DisplayName  = "Russian Spying Service"
        Description  = "Crawls your network for incriminating files to send to the FSB"
        Account      = "[SERVICE_ACCOUNT_NAME]"
        Type         = "ownProcess"
        Arguments    = "-mode service"
        Interactive  = "no"
        Start        = "auto"
        ErrorControl = "normal"
    >
    
        <ServiceConfig DelayedAutoStart="yes" OnInstall="yes" OnUninstall="no"  OnReinstall="yes" />
        <util:ServiceConfig FirstFailureActionType="restart" SecondFailureActionType="restart" ThirdFailureActionType="none" ResetPeriodInDays="1" />
    
    </ServiceInstall>
    
    Run Code Online (Sandbox Code Playgroud)
  3. 构建并运行安装程序并执行升级方案,您将看到在升级安装之间将保留任何自定义服务帐户用户名。

您也可以将此方法推广到其他属性。

免责声明:

  • 微软并没有正式认可用户态程序直接修改HKLM\SYSTEM\CurrentControlSet\Services\注册表项。Windows 服务上的所有操作都应通过记录且受支持的 Win32 服务控制管理器 API:https ://learn.microsoft.com/en-us/windows/desktop/services/service-control-manager
    • 这意味着 Microsoft 可以自行决定更改 Windows 服务配置,使其不再使用该HKLM\SYSTEM\CurrentControlSet\Services\密钥。
    • (这可能会破坏许多第三方软件,如果微软要这样做,他们可能会像他们所做的那样添加某种虚拟化或重新映射系统SysWow6432Node)。
  • LocalService我只用和进行了测试NetworkService。我没有看到如果您在运行升级之前修改服务配置以在安装后使用自定义用户帐户会发生什么。我确实希望在这种情况下它也会保留配置,因为它将对 SCM 中的值执行字符串比较ObjectName,并且它无法访问密码。