Reputation: 131
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)
Upvotes: 13
Views: 46842
Reputation: 1406
I made functions to manage shutdown tasks. You can't get info with shutdown -s -t
; it's better to use schtasks
.
function Schedule-Shutdown { schtasks /create /tn "SchShutd" /tr "shutdown -s -f" /sc once /st $args[0] }
function Schedule-Shutdown-Info { $t=Get-ScheduledTask -TaskName "SchShutd" 2>$null; if ($t){$t.Triggers.StartBoundary}else{"No task found"} }
function Schedule-Shutdown-Cancel { schtasks /delete /tn "SchShutd" /f }
Usage:
Schedule-Shutdown 15:00
SUCCESS: The scheduled task has been created.
Schedule-Shutdown-Info
2025-01-10T15:00:00
Schedule-Shutdown-Cancel
SUCCESS: The scheduled task was deleted.
Schedule-Shutdown-Info
No task found
Place the functions in your PowerShell profile file to make it globally available.
notepad $PROFILE # opens your profile file, paste here
Enable script running
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Upvotes: 0
Reputation: 1
//
// 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($"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.");
}
}
Upvotes: -2
Reputation: 1
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
Upvotes: -2
Reputation: 31
You can use:
Shutdown /a "for aborting the scheduled"
then use shutdown again to create another schedule.
Upvotes: 3
Reputation: 171
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.
Upvotes: 6
Reputation: 133
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.
Upvotes: 0
Reputation: 4215
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)
Upvotes: 0
Reputation: 47954
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.
Upvotes: 0