1

Auto Shutdown if user is inactive.

I am trying to create a one time powershell script to shut down the pc if the user is inactive for a period of time.

I have done some looking around but the only answer to my problem was using VB. The task scheduler is not the answer as the users might be inactive for more than 2 hours.

mklement0
  • 382,024
  • 64
  • 607
  • 775
eruannaa
  • 11
  • 2
  • 1
    "[...] the users might be inactive for more than 2 hours and do not require these PC's to turn off." - so you want the PC to shut down, but you don't want it to shut down? You're gonna have to describe this paradox a little further :) – Mathias R. Jessen Jun 02 '23 at 12:47
  • If _hibernation_ is acceptable too, you could look into a `powercfg.exe`-based solution - see [this post](https://stackoverflow.com/q/65156768/45375), for example. – mklement0 Jun 02 '23 at 13:27
  • @MathiasR.Jessen Sorry, what i meant is the users who are inactive for longer than two hours will require the PC's to shutdown, so Task Scheduler won't work. (Have updated the post) – eruannaa Jun 02 '23 at 14:50
  • 1
    @mklement0 unfortunately, need the PC's to shutdown. I had a look through that post. – eruannaa Jun 02 '23 at 14:54
  • 1
    Understood re shutdown, but I'm still unclear on why a scheduled task with an on-idle trigger that runs the task after 2 hours of being in the idle state won't work. – mklement0 Jun 02 '23 at 17:09
  • Do you truly want to shutdown if there is not user activity on the machine after X time, as in shutdown and not sleep, etc. right? What would an example of the "x" inactivity time be? I have a few ideas but it is clear 2 hours is not what you are after, I get that. – Bitcoin Murderous Maniac Jun 03 '23 at 02:37
  • @BitcoinMurderousManiac the inactivity time would be 5 hours. This is to not have computers running over night (when users shifts are up) – eruannaa Jun 03 '23 at 09:51
  • 1
    @mklement0 This would actually work. I was thinking it wouldn't as the task scheduler only goes to a max of 2h. But if the task scheduled was to start only after 3h of idle then the 5h would be my solution – eruannaa Jun 03 '23 at 10:50
  • 1
    Yes, I'd start with Task Scheduled and manually plugging in the value by clicking on it and then typing in 5 for 5 hour as per this screen shot: https://i.imgur.com/jAbp07q.png with those options both set. Otherwise, I have some other ideas that do not involve that options using strictly PowerShell to go about it another way with a routine task. Start with the simple though as suggested and see if that suffices. If for some reason that does not work, ping back and I'll be happy to provide another potential solution. – Bitcoin Murderous Maniac Jun 03 '23 at 11:55

1 Answers1

1

The task scheduler is not the answer as the users might be inactive for more than 2 hours.

As Bitcoin Murderous Maniac points out in a comment: While the Task Scheduler GUI (taskschedm.msc) seemingly limits you to a maximum idle duration period of 2 hours, you're actually free to type in larger values (include the word hours and submit with Enter):

Unfortunately, however this idle timeout is no longer supported (from the docs):

The Duration and WaitTimeout settings are deprecated. They're still present in the Task Scheduler user interface, and their interface methods may still return valid values, but they're no longer used.

De facto, as of Windows 11 22H2, the behavior of on-idle tasks appears to be limited to the following, based on my experiments (do tell us if you find information to the contrary; the linked docs hopefully still accurately describe the conditions when a computer is considerd (not) idle):

  • The task is launched instantly when an idle condition is detected (which happens after a hard-coded 4 minutes at the earliest).

  • When the computer is no longer idle, the launched task is instantly terminated - that is, the check box in the Task Scheduler GUI that seemingly allows the task to continue to run is no longer effective.

  • When the computer is idle again, the task is invariably restarted - that is, the check box in the Task Scheduler GUI that seemingly allows the task not to restart after having previously been terminated is no longer effective.


However, you can build on these behaviors to achieve what you want:

  • When the task is launched on entering the idle state, first launch a Start-Sleep command that waits for the desired duration, e.g. 5 hours, and only then call Stop-Computer.

  • If the computer stays idle for that long right away, the shutdown will occur as planned.

  • If the computer exits the idle state before that, your task is terminated, so that no premature shutdown occurs - and then restarted the next time the idle state is entered.


The following is self-contained code that sets up such a task:

  • It runs the task as NT AUHTORITY\System, invisibly, and irrespective of whether a user is logged on or not.

    • In order to set up a task with this user identity, you need to run the code in an elevated session (run as admin).
  • The only way to guarantee that a shutdown is not just initiated but completes, -Force must be passed to Stop-Computer. Note, however, that this means that any unsaved data in a user's session may be lost.

  • No PowerShell script (*.ps1 file) is necessary - the commands are passed to powershell.exe, the Windows PowerShell CLI, via its -Command parameter.

  • See the comments in the source code for additional information.

#requires -RunAsAdministrator

# Specify the number of hours of idle time after which the shutdown should occur.
$idleTimeoutHours = 5
# Specify the task name.
$taskName = 'ShutdownAfterIdling'

# Create the shutdown action.
# Note: Passing -Force to Stop-Computer is the only way to *guarantee* that the
#       computer will shut down, but can result in data loss if the user has unsaved data.
$action = New-ScheduledTaskAction -Execute powershell.exe -Argument @"
  -NoProfile -Command "Start-Sleep $((New-TimeSpan -Hours $idleTimeoutHours).TotalSeconds); Stop-Computer -Force"
"@

# Specify the user identy for the scheduled task:
# Use NT AUTHORIT\SYSTEM, so that the tasks runs invisibly and
# whether or not users are logged on.
$principal = New-ScheduledTaskPrincipal -UserID 'NT AUTHORITY\SYSTEM' -LogonType ServiceAccount

# Create a settings set that activates the condition to run only when idle.
# Note: This alone is NOT enough - an on-idle *trigger* must be created too.
$settings = New-ScheduledTaskSettingsSet -RunOnlyIfIdle

# New-ScheduledTaskTrigger does NOT support creating on-idle triggers, but you 
# can use the relevant CIM class directly, courtesy of this excellent blog post:
# https://www.ctrl.blog/entry/idle-task-scheduler-powershell.html
$trigger = Get-CimClass -ClassName MSFT_TaskIdleTrigger -Namespace Root/Microsoft/Windows/TaskScheduler  

# Finally, create and register the task:
Register-ScheduledTask $taskName -Action $action -Principal $principal -Settings $settings -Trigger $trigger -Force
mklement0
  • 382,024
  • 64
  • 607
  • 775