【问题标题】:C# Windows Service that runs a install package problem运行安装包问题的 C# Windows 服务
【发布时间】:2023-04-02 23:45:01
【问题描述】:

我设计了一个windows服务,它会定期检查是否安装了特定的应用程序,当它发现它没有安装时,它会从共享网络位置下载它,该文件是一个静默无人值守的安装exe(自行安装) .

我在运行安装程序时遇到问题,所以我决定不尝试运行安装程序,而是运行一个小型 hello world windows 窗体应用程序,看看这个简单的事情是否有效。

经过几个小时的困惑后,我终于发现 hello world 应用程序确实运行但在不同的用户下运行 - 特别是本地计算机。在接下来的几个小时里,我发现我必须关闭 UAC (Vista/7) 并允许服务与桌面交互。在这之后,我终于在我的桌面上得到了一个提示,一个服务正在尝试运行某些东西,我必须决定是否允许它。

当我按下允许时 - 我被带到另一个 GUI(不同于我的桌面),此后 hello world 正常运行。

现在,虽然这肯定是一个进步,但我距离在当前用户帐户下安装应用程序还有很长的路要走。

我遇到的一个问题是将 Windows 服务设置为以特定用户身份运行,当我在那种 WS 上使用 installutil.exe 时,它​​会提示我输入用户名和密码,我输入正确的(管理员权限)数据并且安装失败。

我想要实现的是让 Windows 服务安装一个静默安装包而不会以任何方式中断用户,测试静默安装包是 net framework 2.0 - 我需要安装它,就好像用户自己点击它一样.

我不需要任何代码(但这会受到欢迎),只需指出正确的方向,提前感谢!

【问题讨论】:

  • 我不确定问题是什么,但 Windows 服务、屏幕保护程序和其他系统进程在不同的 UI 上下文或不同的桌面中运行。我记得,可以让 GUI 在登录用户的上下文中运行(如果有的话)。

标签: c# windows windows-services service


【解决方案1】:

我不知道它是如何在 C# 中完成的,但我会解释一下这个概念。

当您使用 Windows 服务时,您的应用程序运行一个 SYSTEM 用户,因为该应用程序甚至在执行任何登录之前就已运行。

此外,由于重大安全问题,例如导致应用程序运行 cmd.exe 任何类型的资源管理器允许用户执行他/她不应该做的事情(我认为你可以绕过它,不确定,但无论如何都不推荐,所以不要)。

所以你有两个选择:

  1. 创建另一个将在用户会话下运行的应用程序,您可以使用 RPC 与其通信(如 .Net 远程处理)。您可以将应用程序放在用户的启动中。

  2. 我认为更好的方法是使用 CreateProcessAsUser()(我不知道它在 C# 中是如何调用的)。每个用户都有一个令牌,因为您是一个服务,您有权获取用户的主令牌,这将允许您在用户帐户下创建进程。 CreateProcessAsUser() 创建一个进程,并且它还获得一个令牌以作为该用户运行该进程。

关于令牌的更多信息,对于 CreateProcessAsUser,您需要获取用户的令牌。从 Windows 服务(并且只有 Windows 服务)执行此操作的最简单方法是使用 WTSQuestUserToken。您将用户会话的 sessionID 提供给该函数,然后您将获得一个主令牌。

这种方法并不完美,但它很简单,适用于大多数情况。如果有 2 个用户在同一个 sessionID(sessionID == 终端服务器会话 ID)下,它将不起作用,这可以使用资源管理器中的 Run As 来完成。但我认为我得到的这个答案已经够复杂了,所以如果你的 WTSQueryUserToken() 对你来说不够好,请告诉我,我会更彻底地解释(显然会更复杂)。

祝你好运!

【讨论】:

  • 管理层认为这将是最好的解决方案——我从一开始就反对它。同时,我确实设法向管理层强调,由于时间是这里的第一大问题,我们只需要重构整个逻辑。
  • 因此,我将一个小应用程序部署为无人值守的静默 Inno 安装程序包,此帮助应用程序将计划事件(在用户登录时)添加到任务计划程序 - 启动我需要的应用程序。
  • 另一个额外的好处是 - 能够通过 VBScript 在许多机器上推送这样的包(Inno Setup)。所以基本上我们通过使用不同的方法实现了同样的事情。当然,管理层希望我继续调查 Windows 服务的问题,因为这些仍然是他们的兴趣点,出于某种原因,他们认为它们是 100% 可靠的(例如,与任务调度程序相反)
  • 在我们的具体情况下,我们的用户不会使用“运行方式”,因为他们不知道如何执行此操作(结果证明对我们有好处)并且因为当前的政策禁止他们这样做这个(至少它应该这样做,得问管理员)。因此 - WTSQueryUserToken 应该足以满足我们的需求。再次叹息..win32API ......对它的感觉很复杂 - 一方面它像一个魅力,坚如磐石,有据可查之类的东西,另一方面 pinvoking 有点拖累,特别是如果你没有方法pinvoke 网络上列出的 sig :)
  • 为什么不在项目中添加一些 c++.net dll?它允许本地代码和托管代码的简单混合。这意味着您不需要所有 p/invoke 内容,只需包含正确的标题! :-)
【解决方案2】:

如果您好奇,您会在我的回答 herehere 中找到关于为什么您看到您所描述的行为的足够详细的解释。

但无论如何,解决方案是寻找替代方法。 Windows 服务无法显示用户界面,也无法在特定用户的上下文中运行。对于您想做的事情,它们根本不是一个可行的选择。禁用 UAC 也是可接受的选项。

很难想象为什么首先需要从 Windows 服务执行此操作。用户登录时运行的后台进程似乎是更好的方法。它根本不需要任何界面,但它仍然可以弹出一个窗口或在用户选择时与用户进行交互。

【讨论】:

  • 我同意。尤其是在禁用 UAC 部分。
  • 有人认为 Windows 服务是放置应用程序的最佳位置,该应用程序检查网络驱动器中的 exe,如果 exe 满足某些要求,则下载并安装它。我们这里没有 AD,因此管理层希望我们设计一种通过网络部署应用程序的方法。他们设计了规范,其中 Windows 服务定期检查文件的网络位置,如果需要,下载并安装它(另一个考虑因素是为此运行带有进度条的 GUI)。
  • @Bruno:不幸的是,认为那是错误的人。这是行不通的。当您让对编程一无所知的人开发您的规范时,就会发生这种情况。与现实世界完全脱节的规范对任何人都没有任何好处,即使是那些编写它们的人。在 Windows 服务上拥有一个 GUI(带或不带进度条)简直是不可能。这不是他们的设计目的。阅读您的其他 cmets,我更加相信后台进程就是答案。改为实施;如有必要,编写您自己的规范。
猜你喜欢
  • 1970-01-01
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多