PowerShell How-To

How To Force PowerShell to Wait for Scheduled Tasks

Learning this handy technique will also allow you to add timers to different types of tasks.

Most of the time when writing ad-hoc PowerShell scripts, you'll most likely be writing synchronous tasks. These are tasks that run in serial which inherently wait for the previous task to complete before starting up. There's no reason to explicitly force a command to wait because that's just what it inherently does in the first place. However, there are also times when those commands may take a long time and are run asynchronously. Most of the time it's not important to wait on them to run the next command but you'd like the option to do so.

A good example of a possible asynchronous command is Restart-Computer. When invoked with only mandatory parameters, Restart-Computer will invoke a restart but will immediately release control once it's done that. It will not wait around to see if the computer actually restarted. Restart-Computer has a Wait parameter for that. The same can be said for scheduled tasks but, unfortunately, PowerShell doesn't have a built-in method to wait for one. That's what we're here for.

PowerShell has some built-in functions as of Windows 8 and Windows Server 2012 R2 for managing scheduled tasks, but none include a Wait-ScheduledTask command. Granted, a scheduled task is usually going to be executed asynchronously but there are times when it'd be nice just to wait on one. Let's create a PowerShell function to do this.

To create a custom Wait function like this usually means running a Get command over and over again and checking the expected result. In our case, we've got the Get-ScheduledTask command. This is a built-in command that will return the state of the task. Through testing, I've confirmed that when a scheduled task is not running, the state will be Ready and, when running, will be Running. We first need to come up with a line to gather the state.

This line will accomplish that task.

(Get-ScheduledTask  -TaskName 'NameHere').State

Rather than running this over and over ourselves and checking to see if the state changes from Running to Ready, let's automate that and create a loop that does it for us. We need to run this loop while the state is not Ready. Let's create a PowerShell while loop to invoke Get-ScheduledTask over and over again until the state is not equal to Ready. This will ensure the function does not return control until the scheduled task is set to Ready.

while ((Get-ScheduledTask -TaskName 'TaskNameHere').State  -ne 'Ready') {
Write-Verbose -Message "Waiting on scheduled task..."
}

At its most basic, this command alone would wait until the scheduled task has completed. However, we're not accounting for an important condition. We're not accounting for when, for whatever reason, the scheduled task runs indefinitely. We don't want to just wait on it forever. Let's create a timeout and only wait on it for a specified time. One way to do that is by using the Diagnostics.StopWatch .NET object. This object has a StartNew() and Stop() method which stops a counter and includes an always up-to-date Elapsed property which indicates how much time has passed since StartNew() was invoked.

Using this object, we can start the timer right before we begin to check on the scheduled task and then instead of just checking for the state change, also ensure that the time elapsed did not exceed some threshold.

$timeout = 60 ##  seconds
$timer = [Diagnostics.Stopwatch]::StartNew()
while (((Get-ScheduledTask -TaskName 'TaskName').State -ne 'Ready') -and ($timer.Elapsed.TotalSeconds -lt $timeout)) {   
Write-Verbose -Message "Waiting on scheduled task..."
Start-Sleep -Seconds 3  
}
$timer.Stop()
Write-Verbose -Message "We waited [$($timer.Elapsed.TotalSeconds)] seconds on the task 'TaskName'"

You can see above how this technique could be implemented. We're adding a condition to the loop and checking it after each iteration of the loop as well as the scheduled task's state. Once we're done waiting, it then stops the timer and optionally shows us how long we waited for the scheduled task to complete.

Using this while loop technique and timer can be applied to lots of different tasks as well. Just figure out the code that checks for the condition and implement that into the while loop's condition. This allows you to wait on just about any task!

About the Author

Adam Bertram is an independent consultant, technical writer, trainer and presenter. Adam specializes in consulting and evangelizing all things IT automation mainly focused around Windows PowerShell. Adam is a Microsoft Windows PowerShell MVP, 2015 powershell.org PowerShell hero and has numerous Microsoft IT pro certifications. He is a writer, trainer and presenter and authors IT pro course content for Pluralsight. He is also a regular contributor to numerous print and online publications and presents at various user groups and conferences. You can find Adam at adamtheautomator.com or on Twitter at @adbertram.

comments powered by Disqus

SharePoint Watch

Sign up for our newsletter.

I agree to this site's Privacy Policy.