您如何等待任务计划程序任务完成批处理文件或C#?

时间:2022-05-10 05:25:27

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. 首先,它启动安装程序(install.exe),安装程序(program.exe)。
  3. Second it launches an instance of the installed program (program.exe). This must be executed after the installation completes.
  4. 其次,它启动已安装程序的一个实例(program.exe)。必须在安装完成后执行此操作。

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:

除了安装程序需要管理员权限并且必须在用户上下文中运行之外,这将是相对简单的。即使有这些限制,这仍然是相对简单的,除了我在Azure辅助角色上运行它,这意味着两件事:

  1. Elevated batch files must be run from a startup task.
  2. 必须从启动任务运行提升的批处理文件。
  3. There is no user context for startup tasks in Azure worker roles.
  4. Azure辅助角色中的启动任务没有用户上下文。

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.

因此,似乎解决方案是在真实用户上下文中将安装程序作为任务计划程序任务运行。但是,这需要注意,然后我需要等待此任务完成才能启动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]).

或者,我可以在单个任务计划程序任务中以菊花链方式链接我的批处理文件中的两个调用(任务计划程序在单个任务中最多支持16个连续事件[需要引证])。

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.

但是,如果我采用这种方法,我的批处理文件将在任务安排后立即终止,而不是在完成任务后立即终止。不幸的是,我必须等到它才能完成我的工作者角色中的任何逻辑。但是,如果我可以检查任务计划程序任务是否已完成C#(没有管理员权限),那么我可以在那里等待它。

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

因此,第二个可行的答案是问题:如何检查任务计划程序任务是否已从C#完成?

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

编辑:我想我会通过MC ND澄清以下答案:

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:

调用schtasks / query / tn yourTaskName / fo列表输出如下内容:

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

for命令循环输出中的每一行。使用分隔符“:”将每一行拆分为两个令牌。如果找到以“Status”开头的行,则该行中分隔符后面的标记存储在变量f中(在上面的示例输出中将为“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.

然后检查变量f以查看它是否与状态“正在运行”匹配。如果状态不是“正在运行”,则假定任务已完成或失败,并且循环退出。如果状态为“正在运行”,则任务仍在运行,批处理脚本会暂停一小段时间,然后再次检查。这是通过进行ping调用来完成的,因为批处理没有sleep命令。脚本完成睡眠后,它会重新启动此序列。

2 个解决方案

#1


10  

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

#2


4  

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

你也可以使用timeout来摆脱hacky ping -n命令。

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

这是MC ND的超时答案。样品中的1代表1秒。

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

#1


10  

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

#2


4  

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

你也可以使用timeout来摆脱hacky ping -n命令。

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

这是MC ND的超时答案。样品中的1代表1秒。

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