简体   繁体   中英

C#: Programmatically Detect Windows Server Has Booted

I'm working on an automation process in C# that is going to remotely reboot a Windows (2008/2012/2016) server and I need to wait until that server is back online before proceeding.

I know 'back online' can be ambiguous, so for my requirements, I need the server to be back at the Ctrl-Alt-Del screen. The reason for this is to have the server in a consistent state before proceeding. In my experience, there are several factors that could prevent the server from reaching this screen, such as installing windows updates that gets stuck in a reboot cycle or getting stuck at 'Waiting for Local Session Manager' etc.

I've spent a few days looking in to this to no avail:

  • The server obviously starts responding to ping requests before it is available
  • System Boot Time occurs before the Server reaches the desired state
  • Any events indicating the system has booted are logged before the desired state
  • I can't simply poll for an essential service - when Windows is applying computer updates prior to logon these services can be already started. Additionally, sometimes a server will reboot itself whilst installing updates at this stage which could result in false positives.
  • Polling CPU activity could also produce false positives or introduce delays

Is there anyway to detect a Windows server has finished booting and is available for an interactive logon?

It sounds like you've covered most of the possible ways I know of. Which makes me revert to brute force ideas. I am curious what you're doing where you can't install a windows service on the box (or is that just not very viable because of the number)

First would just be trying to remote login or whatever, and having some way to test if it fails or not, wait 1 minute, try again. But seems like that might cause side-issues for you somehow?

My idea of a brute force method that wouldn't affect state:

  • Ping every 1-5seconds
  • Once it starts responding
  • wait 5 or 10 or even 15 minutes, whilst still pinging it
  • If pings fail reset that timer (windows updates restart case)
  • Then be pretty confident you're at the right state.

With potentially thousands of servers, I can't imagine 15 minutes each would be a big deal, especially if it is consistent enough to be able to run in larger batches

So I've been able to accomplish this by using a hacky method put seems to work in my test environment.

Note that the el.Current.Name property will equate to the Ctrl-Alt-Del text, so on 2008R2 this is 'Press CTRL-ALT-DEL to log on' and 'Press CTRL-ALT-DEL to sign in.' on 2012R2

I've built a C# console application that uses UI Automation:

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;
            }

        }
    }
}

I can then execute this console application via PsExec, however, because this needs to be launched in the winlogon desktop, which can only be done by running under the local system, PsExec is invoked twice. For example:

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

This is very much a work in progress right now as I can't get the output of the command to pass through to the calling process so I may just look to populate a registry value or write to a file that can be subsequently interrogated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM