Мониторинг заданий Планировщика Windows
Планировщик заданий — это cron для Windows: он запускает бэкапы, выгрузки отчётов и служебные скрипты на серверах и офисных машинах. И так же молчит, когда что-то идёт не так. Упавшее задание показывает код вроде 0x1 в колонке, куда никто не смотрит, а встроенное действие «Отправить сообщение электронной почты» устарело ещё в Windows 8 и Server 2012. Разберём, как читать результаты, обойти частые ловушки и получать алерт, если задание упало или не запустилось.
Что значит «Результат последнего запуска»
| Код | Значение |
|---|---|
0x0 | Программа завершилась с кодом 0 |
0x1, 0x2… | Собственный код завершения программы: 1, 2 и так далее. Для PowerShell 0x1 часто значит, что скрипт выбросил ошибку или не загрузился |
0x41301 | Задание выполняется прямо сейчас |
0x41303 | Задание ещё ни разу не запускалось |
0x41306 | Задание остановлено пользователем или по лимиту времени |
0x800710E0 | Запуск отклонён, обычно из-за учётной записи или её прав |
Вкладка «Журнал» по умолчанию пустая. Включите её командой «Включить журнал всех заданий» на панели действий планировщика.
Частые ловушки
- «Выполнять только для пользователей, вошедших в систему». На сервере, где никто не залогинен, задание не запустится. Выберите «Выполнять для всех пользователей» или запускайте от
SYSTEM. - Пустое поле «Рабочая папка». Задание стартует в
C:\Windows\System32, и относительные пути в скрипте указывают туда. Заполните рабочую папку или используйте полные пути. - Подключённые сетевые диски.
Z:\существует только в интерактивном сеансе. Используйте UNC-пути вроде\\nas\backups. - Политика выполнения. Запускайте скрипты PowerShell как
powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Jobs\job.ps1, а не одним файлом.ps1. - Электропитание. На ноутбуке по умолчанию включено «Запускать только при питании от электросети».
- Лимит времени. По умолчанию включено «Останавливать задачу, выполняемую дольше 3 дн.». Зависшее задание до тех пор блокирует следующие запуски.
- Коды завершения PowerShell. Скрипт без
exitв конце возвращает 0, даже если команды внутри упали. Завершайте его явно:exit $code.
Обёртка, которая сообщает в Heartcron
Вместо самой задачи запускайте этот скрипт. Он сообщает о старте, запускает задачу и отправляет код завершения вместе с концом вывода. Работает в Windows PowerShell 5.1 и PowerShell 7:
# C:\Jobs\run-backup.ps1
$url = "https://ping.heartcron.com/<uuid>"
try { Invoke-RestMethod "$url/start" -TimeoutSec 10 | Out-Null } catch {}
$out = & "C:\Jobs\backup.exe" --full *>&1 | Out-String
$code = $LASTEXITCODE
if ($null -eq $code) { $code = 0 }
if ($out.Length -gt 100000) { $out = $out.Substring($out.Length - 100000) }
try { Invoke-RestMethod "$url/$code" -Method Post -Body $out -TimeoutSec 10 | Out-Null } catch {}
exit $code
- Ненулевой код завершения — это ошибка, и алерт уходит сразу, вместе с выводом.
- Если задание вообще не запустилось — машина выключена, задание отключили или удалили, — пинг не придёт, и алерт придёт после запаса времени.
exit $codeсохраняет результат и в самом планировщике.
Если задача сама — скрипт PowerShell, вызывайте её как & powershell.exe -NoProfile -File C:\Jobs\backup.ps1, чтобы заполнился $LASTEXITCODE, и завершайте тот скрипт через exit.
Создайте задание
В PowerShell от имени администратора запланируйте обёртку на каждую ночь в 3:00 от SYSTEM:
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File C:\Jobs\run-backup.ps1" `
-WorkingDirectory "C:\Jobs"
$trigger = New-ScheduledTaskTrigger -Daily -At 3am
Register-ScheduledTask -TaskName "Nightly backup" -Action $action -Trigger $trigger `
-User "SYSTEM" -RunLevel Highest
Или то же через schtasks:
schtasks /Create /TN "Nightly backup" /SC DAILY /ST 03:00 /RU SYSTEM /RL HIGHEST ^ /TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Jobs\run-backup.ps1"
В Heartcron создайте проверку с cron-выражением 0 3 * * * в часовом поясе машины и запасом времени больше обычной длительности бэкапа. Еженедельные и ежемесячные триггеры тоже переводятся в cron; что значит выражение, покажет расшифровщик cron-выражений.
Проверьте
Start-ScheduledTask -TaskName "Nightly backup"
Get-ScheduledTaskInfo -TaskName "Nightly backup" # LastTaskResult должен быть 0
Проверка в Heartcron должна показать старт и успех с длительностью. Потом один раз заставьте задачу упасть, чтобы увидеть алерт и вывод.
Без обёртки
У открытой утилиты heartcron есть сборка для Windows, и она делает то же, что скрипт выше: heartcron.exe run nightly-backup -- C:\Jobs\backup.exe --full. Укажите эту строку в действии задания.