简体   繁体   中英

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.

From batch file, query the task status, and if it is running, keep querying

: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
    )
)

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
    )
)

thank you! confirmed working on windows 10 cmd file. very useful way to create multiple aysnc tasks and sync them back up. For example, chkdsk multiple drives in parallel and wait for all jobs to finish:

C:\Windows\System32\schtasks.exe /RUN /TN "chkdsk_G"
C:\Windows\System32\schtasks.exe /RUN /TN "chkdsk_H"

:loop

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

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

:both jobs are now complete

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM