检测计划关闭

发布于 2024-11-09 20:34:17 字数 353 浏览 4 评论 0原文

我有一个 cmd 脚本,它将执行一组补丁,它被设计为在需要重新启动时中止以避免补丁问题。我还想扩展脚本以在计划重新启动时中止(例如通过“shutdown”命令),以便尽可能避免在补丁中重新启动。不幸的是,除了尝试安排另一次关闭之外,我还没有找到一种方法来检测这一点,这会导致:

已安排系统关闭。(1190)

虽然理论上我可以使用此功能,但我认为每次需要检查计划的重新启动时吓唬登录用户并不是一个好习惯。我真正需要的是一种查询“关闭”命令修改的状态的方法。

这可能吗?我会对任何不涉及我在系统上永久运行应用程序来捕获关闭事件的解决方案感到满意(我认为在实际触发关闭之前甚至不会发送该事件)

I have a cmd script that will execute a set of patches, and it's designed to abort if a reboot is required to avoid patching issues. I'd also like to extend the script to abort if a reboot is scheduled (E.g. via the "shutdown" command) in order to avoid reboots mid patch if possible. Unfortunately I haven't managed to find a way to detect this apart from attempting to schedule another shutdown, which results in:

A system shutdown has already been scheduled.(1190)

While I could theoretically use this I don't think it would be good practice to scare logged in users every time I needed to check for a scheduled reboot. What I really need is a way to QUERY the state modified by the "shutdown" command.

Is this possible? I'll be happy with really any solution that doesn't involve me having an application running permanently on the system to catch the shutdown events (which I don't think even get sent around until the shutdown is actually triggered)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

猫性小仙女 2024-11-16 20:34:26
    //
    // RestartOrShutdown.cs, Aad Slingerland, oktober 2024.
    // install-package System.Diagnostics.EventLog
    // See also:
    // https://morgantechspace.com/2013/08/convert-datetime-to-ticks-and-ticks-to.html
    // Limitations:
    // English locale only, but the texts "restart" and "power off" can be changed to another locale.  
    //
    using System.Diagnostics;

    namespace RestartOrShutdown;

    internal class Program
    {
       static int Main(string[] args)
       {
           int rc = 0;
           int minutes = 1;
           try
           {
               if (args.Length > 0)
               {
                   minutes = int.Parse(args[0]);
               }
    #pragma warning disable CA1416 // Validate platform compatibility
              EventLog syslog = new("System");
              //
              DateTime _now = DateTime.Now;
              long minus = 10000000;           // one second in ticks
              DateTime _past = _now.AddTicks(-(minus * 60 * minutes));
              //
              Debug.WriteLine(_now.Ticks);
              Debug.WriteLine(_past.Ticks);
              //
              var entries = syslog.Entries.Cast<EventLogEntry>()
                  .Where(x => x.TimeWritten.Ticks > _past.Ticks && x.EventID == 1074)
                 .ToList();
    #pragma warning restore CA1416 // Validate platform compatibility
              //
              foreach (EventLogEntry e in entries)
              {
                  Debug.WriteLine(e.TimeWritten.Ticks);
                  Debug.WriteLine(e.Message);
                  if (e.Message.Contains("restart"))
                  {
                      rc = 1;
                  }
                  else if (e.Message.Contains("power off"))
                 {
                     rc = 2;
                 }
             }
          }
          catch (System.FormatException)
          {
              Usage();
              rc = 9;
          }
          Console.WriteLine(
quot;Returncode={rc}");
          return rc;
     }

     static void Usage()
     {
         Console.WriteLine(@"
         Usage: RestartOrShutdown [minutes]

         Queries the Operating System wether it is in the process of Restart or Shutdown.
         Return code 0 = neither.
         Return code 1 = Restarting in progress.
         Return code 2 = Shutdown in progress.
         Return code 9 = invalid argument value. 
         The argument [minutes] defaults to 1 minute.
         The argument [minutes] tells this program how far to look back in the Windows 
         System Event log for a record with EventID 1074.");
     }
}
    //
    // RestartOrShutdown.cs, Aad Slingerland, oktober 2024.
    // install-package System.Diagnostics.EventLog
    // See also:
    // https://morgantechspace.com/2013/08/convert-datetime-to-ticks-and-ticks-to.html
    // Limitations:
    // English locale only, but the texts "restart" and "power off" can be changed to another locale.  
    //
    using System.Diagnostics;

    namespace RestartOrShutdown;

    internal class Program
    {
       static int Main(string[] args)
       {
           int rc = 0;
           int minutes = 1;
           try
           {
               if (args.Length > 0)
               {
                   minutes = int.Parse(args[0]);
               }
    #pragma warning disable CA1416 // Validate platform compatibility
              EventLog syslog = new("System");
              //
              DateTime _now = DateTime.Now;
              long minus = 10000000;           // one second in ticks
              DateTime _past = _now.AddTicks(-(minus * 60 * minutes));
              //
              Debug.WriteLine(_now.Ticks);
              Debug.WriteLine(_past.Ticks);
              //
              var entries = syslog.Entries.Cast<EventLogEntry>()
                  .Where(x => x.TimeWritten.Ticks > _past.Ticks && x.EventID == 1074)
                 .ToList();
    #pragma warning restore CA1416 // Validate platform compatibility
              //
              foreach (EventLogEntry e in entries)
              {
                  Debug.WriteLine(e.TimeWritten.Ticks);
                  Debug.WriteLine(e.Message);
                  if (e.Message.Contains("restart"))
                  {
                      rc = 1;
                  }
                  else if (e.Message.Contains("power off"))
                 {
                     rc = 2;
                 }
             }
          }
          catch (System.FormatException)
          {
              Usage();
              rc = 9;
          }
          Console.WriteLine(
quot;Returncode={rc}");
          return rc;
     }

     static void Usage()
     {
         Console.WriteLine(@"
         Usage: RestartOrShutdown [minutes]

         Queries the Operating System wether it is in the process of Restart or Shutdown.
         Return code 0 = neither.
         Return code 1 = Restarting in progress.
         Return code 2 = Shutdown in progress.
         Return code 9 = invalid argument value. 
         The argument [minutes] defaults to 1 minute.
         The argument [minutes] tells this program how far to look back in the Windows 
         System Event log for a record with EventID 1074.");
     }
}
能否归途做我良人 2024-11-16 20:34:25

如果您的脚本设置关闭,另一种方法是使用 setx 命令将 %date% 和 %time% 变量保存到全局环境中。然后您可以在下次调用脚本时检查这些变量。

Another way to do this, if your script is setting the shutdown, is to save the %date% and %time% variables into global environments using setx command. Then you can check these variables on the next time that the script is called.

韵柒 2024-11-16 20:34:25

五分钟内我遇到了问题
这很容易
当您收到此错误时`

“无法中止系统关闭,因为没有关闭
进展”`

您所要做的就是再次安排关机时间
通过此命令“shutdown -s -t 300(时间以秒为单位)”
然后通过命令“shutdown -a”取消它
谢谢

In five minutes I got the problem
its very easy
when you receive this error`

"Unable to abort the system shutdown because no shutdown was in
progress"`

All you have to do is again schedule your shutdown
by this command "shutdown -s -t 300 (time in seconds)"
then cancel it by this command "shutdown -a"
thanks

痴意少年 2024-11-16 20:34:24

也许您可以尝试通过调用 ExitWindowsEx 来启动关闭 具有较长的宽限期,并检查返回代码 ERROR_SHUTDOWN_IS_SCHEDULED 并调用 如果 ExitWindosEx 返回成功(表明您成功安排关闭)

Maybe you can try to initiate a shutdown by calling ExitWindowsEx with a large grace period and check for the return code ERROR_SHUTDOWN_IS_SCHEDULED and call AbortSystemShutdown immediately if ExitWindosEx return success (indicating you successfully scheduled a shutdown)

神妖 2024-11-16 20:34:23

I suppose you could use the Task Scheduler API to enumerate the scheduled tasks and see if any of them invoke shutdown.exe. But I"m not sure that's robust. There are probably multiple ways to schedule a shutdown.

风蛊 2024-11-16 20:34:22

您可以使用:

Shutdown /a“用于中止计划”,

然后再次使用 shutdown 创建另一个计划。

You can use:

Shutdown /a "for aborting the scheduled"

then use shutdown again to create another schedule.

地狱即天堂 2024-11-16 20:34:21

我也有同样的问题,我到处搜索,但没有找到任何有用的东西。

最终我开始摆弄我能想到的不同东西。我可以想到解决我们问题的两种方法。

事件查看器可以告诉您已计划关闭,但不能告诉您计划关闭的时间。

一种想法是向事件查看器查询最近的系统关闭、最近的计划关闭以及最近取消的计划关闭。如果计划的关闭比最近的取消或关闭更新,则有一个正在进行中。
事件 ID 为:
1074 开始计划关闭,
1075 表示取消计划关闭,在 Windows 日志/系统下
12 系统启动
13 系统关闭
(全部在 Windows 日志/系统下)

我懒得在批处理文件中执行此操作,但我知道这是可能的。

这就是我最终所做的:
与其安排关闭,不如尝试中止它。如果没有进行任何关闭操作,则会抛出错误(无法中止系统关闭,因为没有进行任何关闭操作。(1116))。我认为比通过安排关闭来吓坏用户要好得多。

这是我为简单的自动关闭脚本编写的代码副本,它在取消和启动计划关闭之间切换。

@echo off
shutdown /a
if errorlevel 1 call:shutdown
goto end

:shutdown
    set /p choice=Shutdown in how many minutes? 
    set /a mod=60
    set /a mod*=%choice%
    shutdown /s /t %mod%

:end

编辑 - 我正在重新审视这个答案,因为我有更多信息要添加。

上述解决方案将使用 /t 参数通过 shutdown.exe 命令检测是否已计划关闭。

如果您需要确定 Windows 是否已安排关机(某些 Windows 更新后会自动执行),则可以查询设置的注册表项。以下是在 PowerShell 中进行的,但您可以编写批处理文件来执行相同的操作。

Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending'

注意:如果使用 shutdown.exe 计划重新启动,则不会返回 true,只有当 Windows 表示您的计算机需要重新启动时,它才会返回 true。

I have the same problem, I searched all over, but did not find anything useful.

Eventually I just started messing around with different things I could think of. I can think of two workarounds for our problem.

The event viewer can tell you that a shutdown has been scheduled, but not WHEN it was scheduled.

One idea is to query the event viewer for the most recent system shutdown, the most recent scheduled shutdown, and the most recent cancellation of a scheduled shutdown. If the scheduled shutdown is more recent than either the most recent cancellation or shutdown then there is one in progress.
The Event IDs are:
1074 for a started scheduled shutdown,
1075 for a canceled scheduled shutdown, under Windows Logs/System
12 for system start up
13 for system shutdown
(all under Windows Logs/System)

I was too lazy to do this in a batch file, I know it is possible though.

So this is what I ended up doing:
Rather than schedule a shutdown, just try to abort it. If no shutdown is in progress it will throw an error (Unable to abort the system shutdown because no shutdown was in progress.(1116)). Much better I think than freaking out a user by scheduling a shutdown.

Here is a copy of the code I wrote for a simple auto shutdown script, it toggles between cancelling and starting a scheduled shutdown.

@echo off
shutdown /a
if errorlevel 1 call:shutdown
goto end

:shutdown
    set /p choice=Shutdown in how many minutes? 
    set /a mod=60
    set /a mod*=%choice%
    shutdown /s /t %mod%

:end

EDIT - I am revisiting this answer as I have more info to add.

The Above solution will detect if a shutdown has been scheduled via the shutdown.exe command using the /t argument.

If you need to determine if Windows has schedule a shutdown (as it does automatically after some Windows Updates) then there is a registry entry that is set which you can query. The below is in PowerShell, but you can write a batch file to do the same.

Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending'

Note: this will not return true if a reboot in scheduled using shutdown.exe, it will only return true if Windows says your computer need to be rebooted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文