Pet*_*ter 1 powershell scheduled-tasks task-scheduler
我正在运行 Windows 任务计划程序任务:
Powershell
-command C:\file.ps1 2>&1 > c:\test.log
Run Code Online (Sandbox Code Playgroud)
file.ps1包含
Try{
echo "a"
sleep 5
echo "b"
}
Finally{
echo "c"
}
Run Code Online (Sandbox Code Playgroud)
当我手动启动任务并等待其完成时,test.log 包含“abc”。但是当我通过手动退出(“结束”按钮)来中断它时,它只包含“a”。
我认为Finally甚至是在退出 powershell 脚本时运行?我的预期结果是“ac”
正如 Lieven Keersmaekers 在评论中提到的,当您使用 End 中断任务时,finally 块没有机会运行。这是因为 End 只是终止了该进程。PowerShell 很乐意在执行其他退出操作之前运行finally 块,但是 PowerShell 在进程终止信号之后根本无法执行任何操作 - 它已经死了。任何进程都没有办法处理这个问题。用陈雷蒙的话来说:
TerminateProcess 是低级进程终止函数。它绕过 DLL_PROCESS_DETACH 和进程中的任何其他内容。一旦使用 TerminateProcess 终止,该进程中将不再运行用户模式代码。它消失了。不过去就走。不要收取 200 美元。
不过,有一个解决方法。由于任务计划程序的 End 命令不会终止任务进程的子进程,因此您的主 PowerShell 脚本可以启动看门狗进程来执行任何最终清理。该脚本可能看起来像这样(我们称之为watchdog.ps1):
$watched = Get-Process -Id $args[0]
$watched.WaitForExit()
'Cleanup' >> c:\test.log
Run Code Online (Sandbox Code Playgroud)
它需要一个进程 ID,等待该进程退出,然后才进行一些清理,相当于您的 finally 块。
那么你的主脚本可能如下所示:
$myPid = [System.Diagnostics.Process]::GetCurrentProcess().Id
$watchdog = Start-Process 'powershell' "-c .\watchdog.ps1 $myPid" -PassThru -WindowStyle Hidden
'Starting'
sleep 10
'Finished'
Run Code Online (Sandbox Code Playgroud)
首先,它启动看门狗脚本,并提供自己的进程 ID。然后它继续正常的业务,完成后正常退出。
如果您希望仅在主脚本被中断时才进行看门狗的清理,请将此行添加到主脚本的末尾:
$watchdog.Kill()
Run Code Online (Sandbox Code Playgroud)
这将阻止看门狗继续越过第二行。
您的重定向仅适用于主进程,因此看门狗必须处理其自己的输出方向。根据计划任务的配置,您可能需要将 watchdog 脚本的完整路径放入主脚本的 watchdog-launching 命令中。
| 归档时间: |
|
| 查看次数: |
1216 次 |
| 最近记录: |