Invoke-ConditionalShutdown.ps1

Windows natively won’t let you schedule a system shutdown, but there are plenty of posts on the Internet that show you how to create a Scheduled Task that will do that for you.

Having recently added a solar+battery setup to our home, I’ve been on a (belated) mission to reduce our overnight power consumption, and I’ve decided that a scheduled shutdown of my desktop PC around bedtime would be a good idea. HOWEVER I don’t want it to be completely automatic, because sometimes I might be running a process that needs to be let run. I might have a WinSCP or PowerShell session open to a Pi I’m monitoring, or I’m capturing real-time traffic from KNX’s “ETS” app, and the shutdown would be A Bad Thing. And here’s where I hit a roadblock.

“Invoke-ConditionalShutdown.ps1” is the solution.

Create your scheduled task as required, but instead of calling “shutdown”, call PowerShell, invoke the script, and add some attributes to define a “skip list” of processes to whitelist, or a “skip file” with the power of regular expressions to look for a list of processes and title bar text.

Features

 
Simple modeSupply a comma-separated list of process names to whitelist. e.g. “Notepad++,Bounsky 2015”.
Power-user modeProvide a CSV file naming the process and what its title bar must say for it to be whitelisted. These values are regular expressions, where a blank entry is a wildcard “$true”.
HibernateAll the power, but just hibernate instead of shutting down. (The script will abort and report an error if Hibernate is disallowed for your machine or o/s).
Shutdown timerWindows’ shutdown command has a “-t nn” attribute, and I’ve catered for that here too, with a default 20s delay for some in-built “OMG NOOOO” protection. (“shutdown -a” is your “undo” command here.)
Reopen previously-running appsIf enabled and invoked, when the machine next boots, all the previously-running apps will reopen. See “ARSO” below.
Validate the regex in the SkipFile Not sure if your RegEx is up to scratch? Don’t worry, neither is mine. Run the script with the “-ValidateSkipFile” switch and it will tell you which of your RegEx rules are no good. Rinse and repeat until it’s all valid, then proceed to “TestMode”.
TestModeTest your settings are correct without risking an unexpected shutdown/hibernate event. The script will drop a message to the screen telling you if it would have shutdown or not, and what criteria triggered the ‘skip’. (Run -ValidateSkipFile first if you’re using the SkipFile).
VerboseOutput verbose info to screen.
Code SignedWith thanks to DigiCert, the released version of the script has been signed, so it’ll run in environments where a strict security policy is enforced.

Setup

The most important decision is whether you want to use the simple or power-user modes (although the script’s OK with both at the same time). Regardless of your choice, you’re going to need to know the names of the running processes. That’s as simple as “get-process”.

You can filter to only processes that have a title bar with:

Get-Process | Where { $_.MainWindowTitle} |Select-Object ProcessName, MainWindowTitle

Simple mode

In simple mode, you just need to prepare a comma-separated list of executables, like this:

-SkipList "ETS6N,RDCMan"

Run the script in TestMode to see if it wants to shutdown:

.\Invoke-ConditionalShutdown.ps1 -SkipList "ETS6N,RDCMan" -TestMode

Power-user mode

For Power-user mode you provide a CSV file naming the process and what its title bar must say for it to be whitelisted. These values are regular expressions, where a blank entry is a wildcard “$true”. e.g. a line entry of “,”^\*.*” will whitelist any process where the first character in the title bar is an asterisk, commonly-used to indicate changes have been made and the file has not been saved.

Run the script with the -SkipFileswitch and a filename:

-SkipFile "SkipFile.csv"

The SkipFileneeds to look something like this, with the top row being “Name,Titlebar”:

Name,Titlebar,
notepad\+\+,\*.*
RDCMan,

Note how I’ve had to escape the +’s, because we’re in the wonderful world of RegEx.

This sample file will skip a shutdown/hibernate if NotePad++ is running with a file that hasn’t been saved, or if RDC Manager is running, regardless of the title bar.

Check the validity of your regex with:

.\Invoke-ConditionalShutdown.ps1 -SkipFile "SkipFile.csv" -ValidateSkipFile

Here’s what some bad RegEx looks like:

.. and once your RegEx is good, re-test to see if the file would result in a shutdown or not:

.\Invoke-ConditionalShutdown.ps1 -SkipFile "SkipFile.csv" -TestMode

ARSO – Automatic Restart Sign-On

I think it’s an unfortunate acronym, but ARSO will re-launch any apps that were running next time the machine is restarted. To invoke this, just add the “-reopen” switch to the script.

The “-GetArsoKey” switch it will tell you if your PC is set to allow ARSO.

“-SetArsoKey 0” will enable the feature, and “-SetArsoKey 1” will disable it. You’ll probably need to issue these commands from an elevated PowerShell window.

Creating the Schedule

When you run Task Scheduler you’re presented the options of creating a “Basic Task” or a “Task”. The latter provides FAR more control over your task, including the ability to skip the task if the machine’s not idle, so that’s the one I recommend you choose.

I won’t repeat the process to create a Scheduled Task – I’ve documented it here before – but I will give you the one screen that’s specific to this script to remove any ambiguity. This is the “Action” dialog:

Program/script:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Add arguments:
-Executionpolicy AllSigned -NoProfile -file "Invoke-ConditionalShutdown.ps1" -SkipFile "shutdownSkipFile.csv"

Change “-SkipFile” to “-SkipList” if the simple test is sufficient, and customise the rest of the switches as appropriate.

If you’re NOT using the code-signed version of the script from GitHub, change the “-Executionpolicy AllSigned” to “-Executionpolicy Unrestricted”.

Start in:
<The folder where the script lives>

(You can always leave “Start in:” blank and specify the full drive and filepath for the “-file” value above.)

Risks / Traps

The script is running under PowerShell

You’ll need to be careful if you add PowerShell as a skip condition, because as the script runs in a PowerShell window, your test might always be true and the machine will never reboot!

DON’T add “PowerShell” to your SkipList for this reason. (In a future update I might have the script throw an error if you specify this.)

When the script runs as a Scheduled Task it has no Title Bar, so if you want to skip on an open PowerShell window, then add one of these to a SkipFile:

Name,Titlebar,
PowerShell,<Some title text>
PowerShell,Admin.*

Tray apps have no Title Bar

Another thing to be careful of is that apps minimised to the System Tray don’t have a title bar value. This means your machine will shutdown if a runnning process in your SkipFile has anything other than a wildcard (blank or .*) for its title bar value.

Did It Work?

If you find your machine has mysteriously shutdown, I guess it worked.

Windows will drop an event into your Event Log to record the shutdown, so go looking for look for Event 1074 in the “Windows Logs / System” event folder:

If it DIDN’T shutdown and you were expecting it to, it should log the reason why to the logfile. If not, proceed to Troubleshooting….

TroubleShooting

If you’re having problems with the schedule not working, I suggest first running the script in a PowerShell window to double-check you’ve scraped it OK from GitHub and your command-line parameters are correct. Don’t forget to add “-TestMode” so a successful test doesn’t shut the machine down. Alternatively, add something like “-t 20”, and be prepared to run “shutdown -a” to abort if Windows pops the “I’m about to shutdown” message. (DON’T try the “-t” trick if you’re also using the hibernate switch, as the script ignores the -t switch because that’s an invalid combination for the shutdown command.)

With the script’s correct operation confirmed it’s time to turn your attention to the Task Scheduler.

Shedule errors

Last Run Result 0x8007010B / Additional Data: Error Value: 2147942667

This one will produce some great Google hits, and the result decodes to “the directory name is invalid”. If you’ve used quotes around the path in the “Start in” box, remove them.

If you’re referencing a network drive, I think you’ll have a LOT more success if you move the script to a local drive.

Launch condition not met, user not logged-on

This error is pretty self-explanatory, the trick here being that if the machine’s locked, you’re deemed to be not logged on.

The fix is to edit the Task on the General tab under Security options:

Check for it on the History tab within Task Scheduler, or if you like exploring new places, you’ll find it in the Event Log buried under Applications and Services Logs / Microsoft / Windows / TaskScheduler / Operational as EventID 332.

Task Scheduler completed task / with return code 2147942401

Here’s an example of where the schedule fired as expected, but the expected action did not occur (and nothing was logged by the script).

This is how the failure was reported under the task’s History tab:

In this case I’d created the task with an “-Executionpolicy AllSigned”, but I was still using the (unsigned) development version of the script, and Windows’ security protections blocked the script from running. It would be preferable to source a code-signed version of the script, or water-down the security with “-Executionpolicy Unrestricted”.

Download

You’ll find the script at GitHub.

If you encounter any problems with it, please open an Issue there.

Revision History

15th November 2022. This is the initial publication.

 
– G.

Leave a Reply

Your email address will not be published.

... and please just confirm for me that you're not a bot first: Time limit is exhausted. Please reload the CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.