【问题标题】:Set the role of a .NET Windows service at install time...from app.config settings在安装时设置 .NET Windows 服务的角色...从 app.config 设置
【发布时间】:2012-05-14 18:04:56
【问题描述】:

我有一项服务,在安装时会将 Myapp.exe.config 文件(基于 app.config 文件生成)放入安装目录。在安装过程中,我需要此文件中的详细信息来配置安装。特别是我需要调整服务的 ServiceProcessInstaller 实例的帐户/用户名/密码字段,以便在它运行时以特定用户身份运行。

但是,在安装过程中,安装程序还没有设置我的注册表设置,也没有将我的 Myapp.exe.config 复制到安装目录...所以我无法提取这些值,这意味着我的服务无法安装作为正确的用户。我现在能做到的唯一方法是将用户/传递值硬编码到 ProjectInstaller 类中,但我不能让自己这样做。这是错误的。

是否有关于如何以特定用户身份安装服务以及如何在安装过程中访问这些凭据的 Windows 安装最佳做法。

目前我正在尝试类似:

namespace MyService
{
   [RunInstaller(true)]
   public partial class ProjectInstaller : System.Configuration.Install.Installer
   {
      public ProjectInstaller()
      {
         InitializeComponent();

         //Set the user credentials.
         //NOTE: Eventually this needs to be updated to pull these values out of a
         //      conf file.  The problem now is that the location of the conf file
         //      is tied to a registry entry for the location of the service which
         //      may or may not exist when this block is executed.
         /* This is the only way I can get it to work, but this is
          * too horrible to ever actually do it this way:
         serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.User;
         serviceProcessInstaller1.Username = "DOMAIN\\user";
         serviceProcessInstaller1.Password = "password";
          */

         // Try to pull the service's registry values to know where it installed:
         RegistryKey keyService = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\services\\MyService");
         string path = ((string)keyService.GetValue("ImagePath"));
         path = path.Substring(1, path.LastIndexOf('\\'));

         string user = someValueFromFileIOontheAbovePath1,
                pass = someValueFromFileIOontheAbovePath2;

         serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.User;
         serviceProcessInstaller1.Username = user;
         serviceProcessInstaller1.Password = pass;
         //Doesn't work because install isn't complete and there aren't reg settings
         // yet, and even if I had the path the .config file is not written yet so
         // there's no file to parse.
      }
   }
}

一些包含这些参数的 .config 文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <appSettings>
      <add key="User" value="DOMAIN\bob"/>
      <add key="Password" value="secret"/>
   </appSettings>
</configuration>

如何在安装期间提取这些用户/密码值而不将它们硬编码到二进制文件中?

谢谢。

【问题讨论】:

  • 您使用的是 Visual Studio 内置的 MSI 设置吗?
  • @ErikPhilips 感谢您的评论。无论如何,我在我的解决方案中添加了一个简单的部署项目 (vdproj),它在构建时会发出一个设置和 .msi 文件。尽管部署项目实际上所做的只是访问我的服务内部的 ServiceProcessInstaller 对象。

标签: c# .net windows service


【解决方案1】:

有许多选项具有不同的安全级别。

1) 如果您指定 ServiceAccount.User 但不提供用户名和密码,Microsoft 的类将弹出一个窗口供您输入凭据。这是非常安全的,因为凭据永远不会存储在任何地方,但是弹出窗口并没有真正让运行安装程序的人清楚他们正在输入的内容。此外,弹出窗口与其他安装屏幕并不能很好地配合。

2) 您可以让 MSI 将用户名和密码作为参数传递给您的安装程序类。这些值以纯文本形式保留在 InstallLog 文件中,因此您肯定要删除它。

3) 让 MSI 使用 DPAPI(System.Security.Cryptography.ProtectedData 类)加密注册表中的名称/密码,然后将它们解密并在您的服务安装程序类中使用它们。

【讨论】:

  • 有趣。我不知道那是行为。如果我不能让它以任何其他方式工作,这是一个选择。
【解决方案2】:

使用 MSI 完成您想要的任务的一种方法是在提交时使用自定义操作来运行您的自定义对象安装程序。提交操作在文件被复制后运行,因此文件将存在于用户选择的安装目录中。

【讨论】:

  • 谢谢埃里克。提交时我知道我可以运行其他一些可执行文件,但是有什么方法可以在我的服务代码中访问 ServiceProcessInstaller 吗?除了 inside 这个对象在服务本身的代码之外,我不知道在其他任何地方我可以实际设置用户/通行证。
  • 我几乎总是将我的 Windows 服务编写为带有参数的自安装程序,然后在提交时手动运行 EXE。这是我个人的偏好,因为如果安装程序本身损坏或 exe/msi 出现问题,手动删除服务可能会非常痛苦。
猜你喜欢
  • 2019-03-24
  • 2019-07-21
  • 1970-01-01
  • 2013-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多