【问题标题】:C#: Programmatically Detect Windows Server Has BootedC#:以编程方式检测 Windows Server 已启动
【发布时间】:2018-12-26 21:44:21
【问题描述】:

我正在使用 C# 进行自动化进程,该进程将远程重启 Windows (2008/2012/2016) 服务器,我需要等到该服务器重新联机才能继续。

我知道“重新联机”可能不明确,因此根据我的要求,我需要服务器返回 Ctrl-Alt-Del 屏幕。 这样做的原因是在继续之前让服务器处于一致状态。根据我的经验,有几个因素可能会阻止服务器到达此屏幕,例如安装 Windows 更新时卡在重启周期或卡在“等待本地会话管理器”等。

我花了几天的时间研究这个无济于事:

  • 服务器显然在 ping 请求可用之前就开始响应它
  • 系统启动时间发生在服务器达到所需状态之前
  • 任何表明系统已启动的事件都会在所需状态之前记录
  • 我不能简单地轮询一项基本服务 - 当 Windows 在登录前应用计算机更新时,这些服务可能已经启动。此外,有时服务器会在此阶段安装更新时自行重启,这可能会导致误报。
  • 轮询 CPU 活动也可能产生误报或引入延迟

是否有办法检测到 Windows 服务器已完成启动并可用于交互式登录?

【问题讨论】:

  • 也许将您的检测代码作为延迟启动服务运行? stackoverflow.com/questions/11015189/…
  • 我忘了提到我无法在这些服务器上安装 Windows 服务。我可以创建一个可执行文件并通过 PsExec 或 PowerShell 调用。问题是检测代码是什么,我不知道如何检测所需的状态。
  • 也许可以创建一个服务并将其部署到自动启动...并 ping 该服务
  • 服务的问题是它可能在到达 Ctrl-Alt-Del 屏幕之前启动,因此轮询它直到它运行可能会产生误报。此外,如上所述,我无法在这些服务器上安装 Windows 服务 :(
  • 您知道您可以将窗口配置为使用存储在注册表中的给定用户和密码自动登录。为什么要等待登录屏幕?

标签: c# winlogon


【解决方案1】:

所以我已经能够通过使用一种 hacky 方法来实现这一点,put 似乎在我的测试环境中工作。

请注意,el.Current.Name 属性将等同于 Ctrl-Alt-Del 文本,因此在 2008R2 上,这是“按 CTRL-ALT-DEL 登录”和“按 CTRL-ALT-DEL 登录” 。 2012R2

我已经构建了一个使用 UI 自动化的 C# 控制台应用程序:

using System;
using System.Windows.Automation;

namespace WorkstationLocked
{
    class Program
    {
        static void Main()
        {
            AutomationElement el = AutomationUI.FindElementFromAutomationID("LockedMessage");

            if (el !=null)
            {
                Console.WriteLine(el.Current.Name);
            }
        }
    }
    class AutomationUI
    {
        public static AutomationElement FindElementFromAutomationID(string automationID)
        {
            string className = "AUTHUI.DLL: LogonUI Logon Window";

            PropertyCondition condition = new PropertyCondition(AutomationElement.ClassNameProperty, className);
            AutomationElement logonui = AutomationElement.RootElement.FindFirst(TreeScope.Children, condition);

            if (logonui != null)
            {
                condition = new PropertyCondition(AutomationElement.AutomationIdProperty, automationID);
                return logonui.FindFirst(TreeScope.Descendants, condition);
            }
            else
            {
                return null;
            }

        }
    }
}

然后我可以通过 PsExec 执行这个控制台应用程序,但是,因为这需要在 winlogon 桌面中启动,只能通过在本地系统下运行来完成,所以 PsExec 被调用了两次。例如:

psexec.exe \\ServerA -s -d C:\PsTools\PsExec.exe -accepteula -d -x C:\Utils\WorkstationLocked.exe

这是一项正在进行中的工作,因为我无法将命令的输出传递给调用进程,因此我可能只是希望填充注册表值或写入随后可以执行的文件审问。

【讨论】:

    【解决方案2】:

    听起来你已经涵盖了我所知道的大多数可能的方式。这让我回归到蛮力的想法。我很好奇你在做什么,你不能在盒子上安装 Windows 服务(或者因为数量而不是很可行)

    首先只是尝试远程登录或其他什么,并有一些方法来测试它是否失败,等待 1 分钟,再试一次。但似乎这可能会给您带来一些副作用?

    我对一种不会影响状态的蛮力方法的想法:

    • 每 1-5 秒 Ping 一次
    • 一旦开始响应
    • 等待 5 或 10 甚至 15 分钟,同时仍在 ping 它
    • 如果 ping 失败,则重置该计时器(Windows 更新重新启动情况)
    • 然后相当自信你处于正确的状态。

    由于可能有数千台服务器,我无法想象每台 15 分钟会是什么大不了的事,尤其是如果它足够一致,可以大批量运行

    【讨论】:

    • 我认为某种“蛮力”方法可能是唯一的选择。我可以检查 logonui.exe 进程是否在会话 1 中运行,这表明服务器已经启动了一些,我无法找到从窗口中提取文本以查找 Ctrl-Alt-Del。显然这是设计使然,因为 winlogon 应该是一个安全的桌面。我真的不喜欢 ping 一段时间的想法,因为它会引入不必要的延迟。安装 Windows 更新有时也需要超过 15 分钟,这意味着投票需要延长。
    • 也许我在硬件方面很幸运,至少在服务包上保持操作系统是最新的。监视logonui 似乎应该是相当可靠的,也许还可以检查其中包含Windows*KB*.exe (以及您知道的任何其他模式)的进程,以便也能够检测Windows 更新(基本上开发一个白名单和一个要监视并决定等待或继续的进程的黑名单)
    猜你喜欢
    • 1970-01-01
    • 2011-01-14
    • 1970-01-01
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    • 2017-09-14
    • 1970-01-01
    • 2011-03-27
    相关资源
    最近更新 更多