Taylor Flatt Taylor Flatt -4 years ago 105
C# Question

Shutdown Windows without Shutdown banner

Very simply, I have created a simple shutdown timer with C# Forms that runs a shutdown command through the command prompt with an associated timer. I have noticed that Windows displays a notification indicating the computer is about to be shutdown just prior to the event (I think it appears no sooner than 15 min or so).

My question is this: Is there a way to stop that popup notification from appearing without interacting with the registry or making intrusive changes in Windows 7/8/10?

I haven't been able to find a good resource on interacting with native Windows (OS) elements like popups and notifications handed out by the OS for these kinds of events. Anyway to catch that event and modify it (like to not display the notification) would be great. But a more permanent solution such as disabling it through the registry or something is also fine. But I'm more interested in a programmatic solution.

Windows 10 Shutdown Notification

Note: If there is no intrusive way of handling this, then I am really open to anything. I'm also trying to re-learn Forms so the exercise is worth it.

Edit: The code is on GitHub and pretty much completed but I would like to add this functionality to it.

Answer Source

Based upon what McNets said in his comment:

Why do not use the std. windows shutdown command? Add a scheduled task that shutdown the system immediately

I decided to leverage the Window's Task Scheduler. I decided to use Task Scheduler but there are others out there that do similar things.

Even though this approach is a bit more involved than just opening up a command prompt, it does everything I need including a circumvention of the shutdown banner that I noted in my question. Note, I can still give the user the option of running it with a banner like I did before but I have yet to implement that functionality. It is pretty trivial though (especially with the base code below). Simply add the timer to the shutdown args instead of /t 1 and set the task to run immediately.

This probably isn't the only solution but it is the least invasive that I could find. Thanks for all the help everyone. I appreciate it.

Full Source on GitHub.

Globals:

public const string DEFAULT_TASK_NAME = "ScheduledShutdownTimer";
private const string SHUTDOWN_COMMAND_ARGS = "/s /c \"Scheduled Computer shutdown via " +
    "the Windows Shutdown Timer App\" /t 1";

Create a task:

using (TaskService ts = new TaskService())
{
    // If the task doesn't exist, create it.
    if (TimerExists(DEFAULT_TASK_NAME))
        throw new TimerExists("The timer already exists in the task scheduler. You " +
        "must modify it instead of attempting to create it!");
    else
    {
        try
        {
            TaskDefinition td = ts.NewTask();
            td.RegistrationInfo.Date = _currentTime;    // DateTime.Now
            td.RegistrationInfo.Source = "Windows Shutdown Timer";
            td.RegistrationInfo.Description = "Shutdown Timer initiated Windows " + 
                "Shutdown Timer";

            td.Settings.Enabled = true;

            td.Triggers.Add(new TimeTrigger(_shutdownTime));
            td.Actions.Add(new ExecAction("shutdown", SHUTDOWN_COMMAND_ARGS, null));

            TaskService.Instance.RootFolder
                       .RegisterTaskDefinition(DEFAULT_TASK_NAME,td);

            Properties.Settings.Default.ShutdownTimer = _shutdownTime;
            Properties.Settings.Default.Save();

            StartLocalTimer();
        }
        catch(Exception)
        {
            DialogResult alert = MessageBox.Show("The timer couldn't be set. ", 
                "Error - Couldn't Set Timer!", MessageBoxButtons.RetryCancel, 
                 MessageBoxIcon.Error);

            if (alert == DialogResult.Retry)
                CreateShutdownTimer(numSeconds);
        }
    }
}

Modify a Task:

using (TaskService ts = new TaskService())
{
    // If the task exists, update the trigger.
    if (TimerExists(DEFAULT_TASK_NAME))
    {
        Task task = ts.GetTask(DEFAULT_TASK_NAME);

        if (task.Definition.Triggers.Count == 1)
            task.Definition.Triggers.RemoveAt(0);

        else if (task.Definition.Triggers.Count > 1)
        {
            for (int index = 0; index < task.Definition.Triggers.Count - 1; index++)
            {
                task.Definition.Triggers.RemoveAt(index);
            }
        }

        // Add the new trigger after making sure it is the only one.
        task.Definition.Triggers.Add(new TimeTrigger(_shutdownTime));

        if (task.Definition.Actions.Count == 1)
            task.Definition.Actions.RemoveAt(0);

        else if (task.Definition.Actions.Count > 1)
        {
            for (int index = 0; index < task.Definition.Actions.Count - 1; index++)
            {
                task.Definition.Actions.RemoveAt(index);
            }
        }

        // Add the new action after making sure it is the only one.
        task.Definition.Actions.Add(new ExecAction("shutdown", SHUTDOWN_COMMAND_ARGS, 
        null));

        // Reset the status in case it was set as anything but "Ready"
        task.Definition.Settings.Enabled = true;
        task.RegisterChanges();

        Properties.Settings.Default.ShutdownTimer = _shutdownTime;
        Properties.Settings.Default.Save();

        // Starts the timer display and enables/disables buttons.
        StartLocalTimer();
    }

    else
        throw new NoTimerExists("The timer doesn't exist in the task scheduler. You " +
        "must create it instead of attempting to modify it!");
}

Stop a task:

using (TaskService ts = new TaskService())
{
    // If the task exists, remove the trigger. 
    // Note: the included Stop() method doesn't work.
    if (TimerExists(DEFAULT_TASK_NAME))
    {
        Task task = ts.GetTask(DEFAULT_TASK_NAME);
        task.Definition.Triggers.RemoveAt(0);
        task.RegisterChanges();
        StopLocalTimer();    // Resets display timers in program
    }

    else
        throw new NoTimerExists("The timer doesn't exist in the task scheduler. " +
            "You must create it instead of attempting to modify it!");
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download