【问题标题】:Updating a package with a Windows Service resets service's account and password使用 Windows 服务更新包会重置服务的帐户和密码
【发布时间】:2015-01-15 02:45:58
【问题描述】:

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

该产品包含一个 Windows 服务,必须将其配置为在每台机器的不同帐户下运行。

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

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

后续更新将包括从更新的 MSI 文件进行安装。

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

  1. 有没有办法配置安装程序,使其在“小”或“次要”更新期间不会更改服务的现有帐户/密码配置? p>

  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>

我曾预计Remove="uninstall" 会在没有更改的情况下保留服务。显然不是。 (如果这发生在“主要”更新中,我不会太担心)。

我还注意到ServiceConfig 元素具有似乎符合要求的属性 (OnReinstall),但根据烛形错误消息,很明显OnReinstall 旨在仅影响元素(PreShutdownDelay 等)而不是整个服务安装。

我已经研究过这些:

奇怪的是,this answer 暗示这只是“重大”升级的问题。那不是我的经验。我的经历是侥幸吗?

在安装过程中提示输入帐户和密码本来可以,但在这种情况下,将密码存储在注册表或其他地方并不是一个真正的选择,并且每次更新都必须重新输入凭据与必须手动重新配置服务。

【问题讨论】:

  • 你有没有深入了解这个?
  • 你得到这个答案了吗?面临同样的问题..任何线索都会很棒...
  • @user2717225,我没有其他线索。我们不必发布很多更新,所以这对我们来说并不像我担心的那么重要。这很麻烦。

标签: wix


【解决方案1】:

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

背景故事:

  • 我们的应用程序安装 MSI 最初使用 LocalService 安装 Windows 服务,但我们的实际桌面软件将其更改为 NetworkService,甚至在某些网络环境中可能需要自定义用户帐户。
  • 我们的&lt;Component&gt; &lt;ServiceInstall&gt; 元素有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>
    
  • 当遵循这些重现步骤时,服务注册/配置将被无意重置:

    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
  • 理想情况下属性值将存储在应用程序自己的注册表项中,并且应用程序有责任确保该值与当前服务配置匹配。
    • 这可以通过在HKLM 中创建一个新的注册表项来完成,该注册表项允许LocalServiceNetworkService(或任何服务帐户)写入它,因此当服务启动时它会记录其用户-帐户名称 - 但这很复杂。
    • 不要使用HKCU 来存储值,因为这不起作用:HKCU 为不同的用户解析为完全不同的注册表配置单元(甚至可能无法加载或访问)。
  • 另一个选项在技术上不受 Microsoft 支持,因为它使用 Windows 注册表自己的 services 注册密钥原始 ObjectName(帐户名称)值 - 这恰好与 AccountName="" 使用的格式相同属性。这也是最务实的,如下所述:

这对我们有用:

  1. 在您的 &lt;Wix&gt; ... &lt;Product&gt;... 元素中,添加此 &lt;Property&gt; 声明和 &lt;RegistrySearch /&gt; 元素:

    <?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>
    
  2. 更新您的&lt;ServiceInstall 元素以使用Account="" 的新SERVICE_ACCOUNT_NAME MSI 属性,而不是以前的硬编码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>
    
  3. 构建并运行您的安装程序并执行升级方案,您会看到在升级安装之间将保留任何自定义服务帐户用户名。

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

免责声明:

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

【讨论】:

  • 不幸的是,使用自定义用户帐户我无法使其完全正常工作。实施此解决方案后,它将保留服务帐户名称,但无法启动服务,我怀疑这是因为缺少提供密码。它会在安装过程中失败,并提示重试/忽略。我只能通过手动打开 services.msc,导航到服务并在安装程序提示/无法成功安装服务的警告期间输入正确的密码,然后单击重试来成功安装。
【解决方案2】:

最终对我有用的是

  <DeleteServices><![CDATA[REMOVE ~= "ALL" AND (NOT UPGRADINGPRODUCTCODE)]]> </DeleteServices>
  <InstallServices><![CDATA[NOT Installed]]> </InstallServices>

我通过一系列试错尝试以及结合其他一些具有类似答案的线程得出了这个答案。

only 不起作用的一个可能原因是 WIX 在重新安装时也会删除该服务。我们只想在初始安装期间安装该服务一次。我们还希望确保在卸载时删除该服务。这是唯一对我有用的条件组合,允许服务保留其设置和用户帐户。

【讨论】:

  • 这对我有用!这两个答案也有助于理解为什么会这样:stackoverflow.com/a/17608049/670028 和 stackoverflow.com/a/321874/670028
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-07
  • 1970-01-01
相关资源
最近更新 更多