How to verify if the system received a shutdown call

1.3k views Asked by At

I'm trying to develop a simple test suite for code that shuts down a Windows system. The requirement is to programatically determine if the system has actually received a shutdown call before it is powered off (to pass this result further to the test suite) and the precise shutdown INITIATION time.

So far I've tried several different approaches none of which seem satisfactory:

1) Monitoring and catching WM_QueryEndSession call

Drawbacks: basically, this call is commonly used to notify running apps and interactive users of the system shutdown. However, this call might not work with a non-responding app or service. Or the actual shutdown might be delayed till the unresponsive services are terminated and apps are closed by the system, even though the call exited with the correct status.

2) Windows Event Log It could be possible to develop a program to read Windows event log. The program would require some time to scan through the event log and verify if the the relevant message was logged or not. But it looks like that would take some time and probably wouldn't complete before the system initiates Event logging service closure and further shutdown. Moreover, running a program during system shutdown doesn't seem reliable.

3) Simply pinging the computer to make sure the network adapter was disconnected from the network. That is not the first action taken in the shutdown process and might be significantly delayed by non-responding processes and other reasons.

Is there any reliable way to catch a shutdown call to the system before the system gets powered off?

1

There are 1 answers

0
Disillusioned On BEST ANSWER

To be honest, my brain is screaming NO. The whole idea seems flawed. It sounds like a desperate attempt to address a symptom of an entirely different problem. Furthermore, testing beyond certain boundaries is generally ill-advised, and with good reason: it over-complicates things to the point where it really is not worth the effort. For example, in this situation where you're testing shutdown:

  • Do you really want to shutdown in the test?
  • What about other application that don't want you to shutdown now?
  • If you do actually shutdown, your app testing the shutdown will go down with the rest of the system.
  • After shutting down, do you automatically restart?
  • If you use the shutdown option to automatically restart - is this going to be the same as a production scenario?
  • Maybe you need a proper power-off and wake-on-LAN to perform a remote restart for a more realistic test?
  • Or perhaps you want to test the shutdown command without actually shutting down?
    • The problem is as soon as you send the shutdown command (successfully), Windows starts shutting down.
    • You could abort the shutdown, but by that time other applications may have been closed in response to the request (not very friendly behaviour).

This is a situation where it is usually more appropriate to mock the interface to the problematic boundary. Then you simply test that the interactions with the mock are correct.

However that said, I still worry that you're trying to address symptoms of a different problem.

You said: "There was a discrepancy with some Windows deployments (not all, though)".
Did you identify the root cause of the discrepancy? If you have an application that's supposed to automatically issue a shutdown command, there are a number of reasons it could fail:

  • The application might not have been running.
  • There might be a bug that prevented it from making the necessary call.
  • It might have made the call, but Windows may have rejected it (Hopefully you ARE checking the return value of the API call?) for some reason (permission, remote sessions, OS in the middle of something else - who knows?).
  • Now, even if the call returns a success result, the shutdown can still be stopped. (BTW, you said you needed to know the initiation time. This is it! This is when shutdown started. Write the current time to a file, in the registry - whatever you like.
  • Even given all of the above, any application can abort the shutdown process. So even if your code that shuts down the system has been thoroughly tested, and works perfectly - some other entirely unrelated app can turn around and say: "ix-nay on the shutdown hey!" - and the system continues running....

Getting back to "symptom of a different problem"... Some things you've said (checking event log, concerned about the time, saying: "catch if the shutdown call was issued to the system") suggest you're trying to find out after-the-fact "was the shutdown command issued"?

This doesn't sound like a testing issue - this sounds like a logging issue.

Perhaps you want to test that this very important logging is happening correctly?
And this brings me straight back to: rather mock the Windows API calls, and test that your interactions with the documented API are correct.

If I haven't dissuaded you from taunting the gods of madness...

You mentioned a drawback to monitoring WM_QueryEndSession of apps/services not responding. However, you don't really care about other apps. You only need one app, your app. A tiny simple stand-alone monitoring utility if necessary. When it gets the message - log it along with the reason. (There's still no guarantee shutdown will complete of course.)

You can go a step further, your monitoring app can use the SetProcessShutdownParameters function to be one of the first processes notified of the shutdown. Of course if shutdown is aborted, your monitoring utility will no longer be running, and will need to be restarted. (Did I mention madness and insanity?)
Alternatively, set it to be one of the last shutdown allowing you to take some action at a time closer to actual shutdown (if it does in fact shutdown).

Your concerns with reading the Event Log were because it might be too slow to finish while the system is shutting down. Why would you even want to read it during shutdown? (Or has the madness taken hold already?) The data is unlikely to run off while the disks are parking off doing nothing. Read it on restart if you have to. But first read about the Shutdown Event Tracker.

Finally, instead of (or in addition to) listening for WM_QueryEndSession, listen for WM_EndSession. There are some situations where the former won't be sent. But as far as I can tell, the latter should always be sent.

Did I mention madness? ... Maybe it was insanity. ... I know I mentioned the loony-bin. ... What who why when how? ... They're inside my head!
The madness ends.