Scripting a Scheduled Wakeup in Windows 7 (and Vista too!)

By , October 15, 2010 1:27 pm

When it comes to implementing power saving settings on managed workstations, the easy part is configuring the power management settings themselves. The hard part is ensuring that the systems remain consistently managed and maintained. Once standby settings are configured in Windows Power Management, idle workstations are likely to enter standby overnight, which is great way for conserving energy. But the evening hours are also an ideal time to deploy software and updates, because it’s less disruptive to employees that use these workstations throughout the day. How do you balance power savings, maintenance, and the end user experience on these systems?

Well, some people will tell you that Wake-on-LAN (WoL) is the solution. It’s true that, with WoL, you should be able to wake machines overnight to perform tasks — in theory at least. I say in theory because, any sysadmin that has tried to use WoL to wake and manage many workstations (100+) over multiple subnets will tell you that Wake-on-LAN is no magic bullet. There are several reasons for this:

  1. To wake up a workstation with Wake-on-LAN, the workstation’s network adapter must be properly configured to receive WoL’s Magic Packets (trust me, these packets are much less magical than their name implies). This can be a lot more difficult than it sounds, especially if you need to script these settings for automated configuration.
  2. In most environments, WoL packets will not work across subnets, so you need at least one device on each subnet that can send WoL packets. You’ll also need some sort of mechanism (usually software) to tell sender devices to send packets on their subnet to wake them up.
  3. Many wireless network adapters do not support WoL, and the ones that do tend to have inconsistent results with receiving WoL packets. If you have workstations that only connect to the network via wireless, this is a problem.
  4. If the workstation is disconnected from the LAN, the WoL packet won’t make it.

Scheduled Wakeups

WoL is very useful for many situations, especially for impromptu wakeups. But if you want your workstations to wake from standby at night, or any time, you may not want to depend soley on WoL. What you really need is something that tells Windows to resume from standby on a schedule. But how? Well, Microsoft Windows actually includes the capability to resume from standby at certain times. This functionality is a part of the Task Scheduler service, and it can be enabled by simply clicking a check box:

With the “Wake the computer to run this task” checkbox set on a scheduled task, the system will resume from standby at whatever time interval has been configured on the Triggers tab. It is important to note, however, that this won’t work if the system is completely powered off.

The next question is, what should the task do once it has woken up the system? The answer is, just about anything. For example, it could run a script that starts Windows Update, run a virus scan, or start a backup. If you can script it or call it from the command line, you can do it. Here’s a simple example of how you might keep the system awake for at ~10 minutes by using the ping command:

Scripting Wakeups

Alright, we can use a scheduled task to wake workstations. That’s great, but not very useful unless we can use a script to automate the creation of a task that does this. As you may already know, a scheduled task can be created with the command line utility: SCHTASKS.EXE. This is a relatively powerful utility for creating tasks, and once you understand all of the command line options, creating a task with this utility is fairly straightforward:

schtasks /create /TN "My Wakeup Task" /SC DAILY /ST 23:00 /TR "ping.exe 169.1.1.1 -n 600 -i 1 -w 1000" /RU "SYSTEM"

Unfortunately, it appears as though there’s no way to set “Wake the computer to run this task” via SCHTASKS. However, Windows Vista and 7 come with a robust Task Scheduler API that can configure this setting. I wrote a VB script that does just that:

'  Name:    ScheduledTaskSetWakeToRun.vbs
'  Author:    Matthew Boyd (iboyd.net)
'  Date:    10/13/2010
'  Purpose:    Enables or disables the "Wake the computer to run this task" setting on Windows Vista and Windows 7 systems.
'        It seems that in order to do this successfully, both in the GUI or via this script,the task compatibility
'        mode must be set to "2.0" or else the setting gets reverted.
'  Usage:    cscript.exe ScheduledTaskSetWakeToRun.vbs "" [enable | disable]
'  Example:    cscript.exe ScheduledTaskSetWakeToRun.vbs "My Scheduled Task" enable
'        The command above would set "Wake the computer to run this task" to enabled.

Option Explicit

Const TASK_UPDATE = &H4
Const TASK_DONT_ADD_PRINCIPAL_ACE = &H10

Dim TaskName, EnableWakeToRun, objTaskService, objRootFolder, objTask, objDefinition

If Wscript.Arguments.Count < 1 Then
 Err.Raise 1, "Invalid command line arguments!"
Else
 TaskName = Wscript.Arguments.Item(0)
End If

Wscript.echo "Task Name: " & TaskName
If Wscript.Arguments.Count < 2 Then 'Set EnableWakeToRun to true by default if enable/disable was not specified.
 EnableWakeToRun = true
 wscript.echo "Action: ENABLE 'Wake the computer to run this task'"
ElseIf UCase(Wscript.Arguments.Item(1)) = "ENABLE" Then
 wscript.echo "Action: ENABLE 'Wake the computer to run this task'"
 EnableWakeToRun = true
Else
 wscript.echo "Action: DISABLE 'Wake the computer to run this task'"
 EnableWakeToRun = false
End If

Set objTaskService = CreateObject("Schedule.Service")
objTaskService.Connect
Set objRootFolder = objTaskService.GetFolder("\")
Set objTask = objRootFolder.GetTask ("\" & TaskName)

Set objDefinition = objTask.Definition
wscript.echo "Current WakeToRun Setting: " & CStr(objDefinition.Settings.WakeToRun)
wscript.echo "Current Compatibility Setting: " & objDefinition.Settings.Compatibility
wscript.echo "---"
objDefinition.Settings.WakeToRun = EnableWakeToRun
objDefinition.Settings.Compatibility = 2
objRootFolder.RegisterTaskDefinition objTask.Name, objDefinition, TASK_UPDATE orĀ  TASK_DONT_ADD_PRINCIPAL_ACE, , , objDefinition.Principal.LogonType

Set objTaskService = CreateObject("Schedule.Service")
objTaskService.Connect
Set objRootFolder = objTaskService.GetFolder("\")
Set objTask = objRootFolder.GetTask (TaskName)
wscript.echo "New WakeToRun Setting: " & CStr(objTask.Definition.Settings.WakeToRun)
wscript.echo "New Compatibility Setting: " & objDefinition.Settings.Compatibility

To use this script, create a task first by using SCHTASKS. Then, run a command similar to this:

cscript.exe ScheduledTaskSetWakeToRun.vbs "My Scheduled Task" enable

The script will output both the previous and new values of the “WakeToRun” setting. You can verify that it worked by opening the Task Scheduler GUI and verifying that “Wake the computer to run this task” is set. This script can also be used to disable this setting.

You may also notice that the code in this script sets the “task compatibility mode” version to 2. I found issues with tasks that were using a different compatibility mode. It seems that “Wake the computer to run this task” would always be reverted, even if it was set through the Task Scheduler GUI. I believe the only disadvantage to changing the compatibility mode is that the task will not be backwards compatible with Windows XP.

By using a combination of Wake-on-LAN and scheduled wakeups, it’s much easier to successfully manage and maintain workstations in standby with better precision and accuracy. Also, by performing maintenance tasks overnight, you can keep workstations reliable without impacting the end user. It’s a win-win situation!

Panorama Theme by Themocracy