Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you wait on a Task Scheduler task to finish in a batch file or C#?

I am trying to write a batch file that does two things:

  1. First it launches an installer (install.exe) which installs a program (program.exe).
  2. Second it launches an instance of the installed program (program.exe). This must be executed after the installation completes.

This would be relatively straightforward except that the installer needs administrator privileges and must run in a user context. Even with these restrictions this would still be relatively straightforward except that I am running this on an Azure Worker Role, which means two things:

  1. Elevated batch files must be run from a startup task.
  2. There is no user context for startup tasks in Azure worker roles.

It therefore appears that the solution is to run the installer as a Task Scheduler task in a real user context. However, this comes with the caveat that I would then need to wait for this task to finish before I could launch program.exe.

Thus, my question is: How do I wait on a Task Scheduler task to finish in a batch file?

Alternatively, I could daisy chain the two calls in my batch file within a single Task Scheduler task (Task Scheduler supports up to 16 sequential events in a single task [Citation Needed]).

However, if I take this approach my batch file will terminate as soon as the task is scheduled, not as soon as it finishes. Unfortunately, I must wait on it to finish before I can do any of the logic in my Worker Role. However, if I can check if a Task Scheduler task has finished from C# (WITHOUT admin privileges), then I can just wait on it there.

Thus a second viable answer would be to the question: How do I check if a Task Scheduler task has completed from C#?

EDIT: I thought I would clarify the below answer by MC ND a bit:

From a high level, this command checks to see if the task is running, and then it sleeps and loops if it is.

:loop
for /f "tokens=2 delims=: " %%f in ('schtasks /query /tn yourTaskName /fo list ^| find "Status:"' ) do (
    if "%%f"=="Running" (
        ping -n 6 localhost >nul 2>nul
        goto loop
    )
)

The call schtasks /query /tn yourTaskName /fo list outputs something like the following:

Folder: \  
HostName:      1234567890  
TaskName:      \yourTaskName  
Next Run Time: 11/27/2030 11:40:00 PM  
Status:        Ready  
Logon Mode:    Interactive/Background 

The for command loops over each line in the output. Each line is split into two tokens using the delimiter ":". If a line starting with "Status" is found, then the token after the delimiter in that line is stored in the variable f (which in the example output above would be "Ready").

The variable f is then checked to see if it matches the status "Running". If the status is not "Running" it is assumed that the task has completed or failed, and the loop exits. If the status is "Running", then the task is still running and the batch script pauses for a short time before checking again. This is accomplished by making a ping call, since batch does not have a sleep command. Once the script is done sleeping it restarts this sequence.

like image 935
Colin B Avatar asked Nov 28 '13 09:11

Colin B


People also ask

What does wait for idle mean Task Scheduler?

Idle wait: The amount of time that the Task Scheduler will wait for an idle state to occur after a task trigger is activated or after the task is started on demand. Idle duration: The amount of time you want the computer to have been idle before starting the task.


1 Answers

You can also get rid of the hacky ping -n command by using timeout.

Here's the answer of MC ND with timeout. The 1 in the sample stands for 1 second.

:loop
for /f "tokens=2 delims=: " %%f in ('schtasks /query /tn yourTaskName /fo list ^| find "Status:"' ) do (
    if "%%f"=="Running" (
        timeout /T 1 /NOBREAK > nul
        goto loop
    )
)
like image 97
Marcell Spies Avatar answered Oct 23 '22 14:10

Marcell Spies