В Windows есть механизм под названием ‘Планировщик заданий’ (Task Scheduler). Основная задача планировщика — выполнение задач в определенный момент времени или при определенном действии. В этой статье будет рассмотрены варианты работы с ним через Powershell. На примере мы создадим задание в виде скрипта с Powershell, изменим и удалим его используя только команды.
Содержание[Скрыть]
- 1 Работа планировщика в Powershell
- 2 Создание выполняемого действия для планировщика
- 3 Создание временного события — триггера
- 4 Регистрация задачи в планировщике
- 5 Запуск и получение дополнительной информации
- 6 Изменение пользователя, параметров безопасности и уровня запуска
- 7 Бэкап, удаление и восстановление задач планировщика с Powershell
- 8 Анализ выполнения и завершения, а так же сравнение
Работа планировщика в Powershell
Отличительной чертой работы Powershell является то, что мы должны создать каждый из объектов (результат команд) планировщика отдельно, а затем объединить их с помощью 1 команды. Сами объекты делятся на следующие:
- Action (Действие) — определяет что мы должны запустить. Действия проявляются как программа (например браузер) с аргументами (открыть определенный сайт). В одной задаче может быть до 32 действий;
- Trigger (Триггер) — это событие при котором должно запуститься действие. Событие может быть привязано к времени или каким-то процессом в системе (включение компьютера, вход пользователя и т.д.). Время можно устанавливать как определенное, например в 14:00, так и интервальное — каждые 2 часа. Так же как и действий триггеров может быть несколько.
- Settings (Настройки) — дополнительные условия обработки задач. Это может быть перезапуск в случае сбоя задачи или самоудаление если задача не используется.
- Security Options (Параметры безопасности) — определяют привилегии и пользователя от имени которого будут запущены задания.
3 и 4 пункт не является обязательными при создании задачи т.к. уже имеет настройки по умолчанию.
За создание задач в планировщике отвечает модуль ScheduledTasks, который имеет следующие команды:
1 |
Get-Command -Module ScheduledTasks |
Создание скрипта для тестирования
Что бы продемонстрировать работу планировщика я создам скрипт, который будет сохранять логи с журнала Windows в папку ‘logs’. Ниже находится сам скрипт:
1 2 3 4 5 6 7 8 9 |
# Папка с логами $log_dir = 'C:logs' # Полный путь до файла с генерацией имени файла в виде даты $log_file = $log_dir + "AppLog_$(Get-Date -format 'dd-mm-yyyy').xml" # Получаем 10 последних логов приложений $logs = Get-WinEvent -MaxEvents 10 -LogName application # Сохраняем результат предыдущей команды в файл в формате XML Export-CliXml -InputObject $logs -Path $log_file -Force |
Команды выше не должны выдавать каких либо ошибок. Ошибка может быть, например, с несуществующей папкой ‘logs’. Сам скрипт я сохранил по пути ‘C:scheduler_task.ps1’. Его запуск не выдает каких-то ошибок:
1 |
.scheduler_task.ps1 |
У вас так же будет создан файл в папке ‘logs’.
Создание выполняемого действия для планировщика
Для создания ‘action’ мы должны указать программу и аргументы. В качестве программы будет сам интерпретатор ‘powershell.exe’, а аргументом будет путь до скрипта. Как говорилось раньше у нас будет несколько объектов (результат команд) и все их нужно будет объединить. Что бы это было возможным мы должны поместить результаты работы в переменные:
1 2 3 |
$task_action = New-ScheduledTaskAction ` -Execute 'powershell.exe' ` -Argument '-File C:scheduler_task.ps1' |
Мы так же можем указать параметр ‘WorkingDirectory’, который определяет откуда и будет запущена программа. Учитывая, что ‘powershell.exe’ виден через системные переменные использовать параметр ‘WorkingDirectory’ нам не требуется.
Действия выше аналогичны следующим настройкам в интерфейсе (т.е. так мы обычно добавляем скрипт Powershell в планировщик):
Создание временного события — триггера
Следующим мы определим, когда мы будем запускать задачу. Это делается с помощью команды ‘New-ScheduledTaskTrigger’. Эта команда имеет множество параметров, которые делятся на системные события и временные.
Системные события, которые мы можем использовать, следующие:
- AtLogOn — во время входа пользователя в систему;
- AtStartup — во время запуска системы.
Аргументы связанные со временем:
- At — точное время выполнение скрипта;
- Daily — ежедневно;
- DaysInterval — интервал в днях. Если указать цифру 1, то подразумевается, что задача будет запускаться ежедневно. Если указать 2 — то задача будет запускаться через день;
- DaysOfWeek — день недели, когда будет выполнен запуск. Возможны варианты: Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday;
- Once — запуск будет выполнен единожды;
- Weekly — запуск по неделям;
- WeeksInterval — интервал между неделями;
- RandomDelay — указывает задержку между запусками. Задержка определяется случайно от указанного значения. Принимает не число, а объект TimeSpan;
- RepetitionDuration — Срок действия задачи. Принимает не число, а объект TimeSpan.
- RepetitionInterval — время через которое задача будет повторяться. Принимает не число, а объект TimeSpan.
Большую часть команд, связанных со временем, мы можем сочетать вместе. Так, например, мы создадим триггер выполнится однажды в 13:00:
1 |
$task_trigger = New-ScheduledTaskTrigger -Once -At 13:00 |
Еще несколько примеров:
1 2 3 4 5 6 |
# Ежедневно в 14:00 New-ScheduledTaskTrigger -Daily -At 14:00 # Запуск каждые 2 дня в 14:00 New-ScheduledTaskTrigger -Daily -DaysInterval 2 -At 14:00 # Каждый 2-ой понедельник в 14:00 New-ScheduledTaskTrigger -Weekly -WeeksInterval 2 -DaysOfWeek Monday -At 14:00 |
Меня интересует ежедневный запуск задачи с периодичностью в 5 минут. Для ‘RepetitionInterval’, который устанавливает такие интервалы, нужно использовать дополнительную команду ‘New-TimeSpan’. В этой команде определим сам интервал:
1 2 |
$time = New-TimeSpan -Minutes 5 $task_trigger = New-ScheduledTaskTrigger -Once -At 0:00 -RepetitionInterval $time |
Регистрация задачи в планировщике
Теперь, после выполнения минимальных требований в виде ‘action’ и ‘trigger’, мы должны объединить эти объекты. Это делается с помощью команды ‘Register-ScheduledTask’. Дополнительно мы можем определить название и описание создаваемого объекта:
1 2 3 4 5 6 7 |
$name = 'Сбор логов' $description = 'Сбор логов приложений каждые 5 минут в папку c:logs' Register-ScheduledTask -TaskName $name ` -Description $description ` -Action $task_action ` -Trigger $task_trigger |
Учитывайте, что вы можете использовать несколько триггеров и действий. Для этого вы должны перечислить их через запятую.
TaskPath указывает где была создана задача. В примере выше это произошло в корне планировщика:
Вы можете использовать аналогичный параметр для регистрации задачи в другой директории:
1 2 3 4 |
Register-ScheduledTask -TaskName 'SomeTask' ` -TaskPath 'Microsoft' ` -Action $action1,$action2 ` -Trigger $trigger1,$trigger2 |
Способа узнать путь два:
- Через графический интерфейс;
- Через команду ‘Get-ScheduledTask’ (будет рассмотрена ниже).
В powershell есть еще одна команда, которая может участвовать в создании задач «New-ScheduledTask». Основное отличие такой команды в том, она не регистрирует (добавляет) задачу в сервис планировщика. Если бы мы использовали обе команды это бы выглядело так:
1 2 3 4 5 |
# Объединение объектов $task = New-ScheduledTask -Action $action1,$action2 `-Trigger $trigger1,$trigger2 # Их активация Register-ScheduledTask -TaskName 'SomeTask' ` -TaskPath 'Microsoft' ` -InputObject $task |
Запуск и получение дополнительной информации
Для запуска задачи, не зависимо от триггеров, используется команда ‘Start-ScheduledTask’:
1 |
Start-ScheduledTask -TaskName 'Сбор логов' |
У нас так же есть 2 команды, которые возвращают информацию о задачах.
Первая команда просто возвращает список задач, которые есть в каталогах планировщика их статус и путь:
1 |
Get-ScheduledTask |
У команды запуска и получения задач из планировщика можно использовать параметры:
- TaskName — имя объекта;
- TaskPath — путь до объекта.
1 |
Get-ScheduledTask -TaskPath '' |
Более полезная команда следующая, так как вернет немного больше информации:
1 |
Get-ScheduledTaskInfo -TaskName 'Сбор логов' |
Само собой все эти команды можно использовать в конвейере:
1 |
Get-ScheduledTask -TaskName 'Сбор логов' | Start-ScheduledTask |
Если задача занимает много времени и ее нужно остановить — можно выполнить следующие действия:
1 |
Stop-ScheduledTask 'Сбор логов' |
Изменение пользователя, параметров безопасности и уровня запуска
Создавая задачи в планировщике мы имеем блок ‘Security Options’, который чаще используется с настройками по умолчанию. В этом блоке определяются следующие параметры:
- Пользователь, от имени которого будет выполнен запуск;
- Выполняется ли задача для вошедших в систему пользователей;
- Привилегии запуска (от пользователя/администратора);
- Совместимость.
В графическом интерфейсе эти параметры настраиваются в следующем блоке:
Так же как и в случае с созданием задачи, в случае ее изменения мы создаем разные объекты (результаты команд), которые затем привязываем через команду ‘Set-SchedukedTask’.
С помощью следующих команд мы изменим пользователя, повысим права и изменим совместимость:
1 2 3 4 5 6 |
# Изменяем пользователя и повышаем права запуска $task_user = New-ScheduledTaskPrincipal -UserId '.admin' -RunLevel Highest # Изменяем совместимость $task_settings = New-ScheduledTaskSettingsSet -Compatibility 'Win8' # Добавляем объекты созданные выше к существующей задаче Set-ScheduledTask -TaskName 'Сбор логов' -Principal $task_user -Settings $task_settings |
Если у вас будет следующая ошибка, то скорее всего она связана с неверным пользователем:
- Set-ScheduledTask : No mapping between account names and security IDs was done.
Само собой эти же объекты можно использовать при создании (регистрации) задачи в планировщике:
1 2 3 4 5 6 7 |
$name = 'Task 3' Register-ScheduledTask -TaskName $name ` -Action $task_action ` -Trigger $task_trigger ` -Principal $task_user ` -Settings $task_settings |
Учитывайте, что у New-ScheduledTaskSettingsSet около 30 возможных параметров (работа при отключенной батареи, максимальное количество перезапусков и т.д.). В примере выше рассмотрено лишь несколько.
Изменение триггеров и действий
С помощью Set-ScheduledTask так же добавляются и изменяются триггеры и действия. Изменение будут заключаться в полной замене существующих триггеров и действий у задач. Вам просто нужно создать объект по аналогии с тем, как это делалось в предыдущих разделах:
1 2 3 4 |
$trigger = New-ScheduledTaskTrigger -Daily -At 14:00 $action = New-ScheduledTaskAction -Execute Calc.exe Set-ScheduledTask -TaskName 'Сбор логов' -Action $action -trigger $trigger |
Бэкап, удаление и восстановление задач планировщика с Powershell
Удобной возможностью использования Powershell является импорт и экспорт задач планировщика. По сути вы можете создать шаблон, который можно использовать на разных компьютерах без особой работы с кодом. По умолчанию, сам Powershell, не предоставляет прямой возможности бэкапа и восстановления, но это можно сделать через другие команды.
Резервное копирование
Для бэкапа мы можем использовать команду Export-CliXml. Для этого нам нужно будет получить задачу и использовать конвейер:
1 |
Get-ScheduledTask -TaskName 'Сбор логов' | Export-Clixml 'C:LogTaskBackup.xml' |
Для экспорта в Powershell так же есть ‘Export-ScheduledTask’, но нет аналогичной команды импорта. Что бы импортировать такие файлы-задачи мы можем использовать только GUI. Из-за этого она не приведена в примере выше.
Удаление, отключение и включение
При удалении задачи, по умолчанию, запрашивается подтверждение. Что бы этого не было добавляется ключ ‘Confirm’:
1 |
Unregister-ScheduledTask -TaskName 'Сбор логов' -Confirm:$False |
Если требуется только отключить задачу используйте Disable:
1 |
Disable-ScheduledTask -TaskName 'Сбор логов' |
Включение:
1 |
Enable-ScheduledTask -TaskName 'Сбор логов' |
Восстановление
Восстановление выполняется в несколько шагов. Первое — мы должны выполнить импорт XML документа в Powershell:
1 |
$task = Import-Clixml -Path 'C:LogTaskBackup.xml' |
На одном из сайтов я прочитал, что следующий параметр нужно изменять на «Interactive», так как без него не будет работать задача, но у меня этот параметр не изменялся при экспорте:
1 |
$task.Principal |
Этот параметр связан со входом пользователя через GUI. Аналогичное название в интерфейсе планировщика задач «Выполнять только для пользователей, вошедших в систему». Если этот параметр у вас отличается — вы сможете изменить его так:
1 |
$task.Principal.LogonType = 'Interactive' |
Далее нам нужно зарегистрировать эту задачу определяя каждый из параметров отдельно:
1 2 3 4 5 6 7 8 |
Register-ScheduledTask ` -TaskName $task.TaskName ` -Action $task.Actions ` -Trigger $task.Triggers ` -Settings $task.Settings ` -Principal $task.Principal ` -User 'administrator' ` -Password '123' |
Анализ выполнения и завершения, а так же сравнение
Используя предыдущие команды мы можем выполнить некоторую автоматизацию. Например так мы можем увидеть результат выполненных задач:
1 |
Get-ScheduledTask | Get-ScheduledTaskInfo | select * |
Часть этих кодов имеет следующую расшифровку (был использован автоматический переводчик):
- 0 — операция успешно завершена.
- 1 — Вызывается неправильная функция или неизвестная функция. 2 Файл не найден.
- 10 — Неправильная среда.
- 267008 — Задача готова к запуску в следующее запланированное время.
- 267009 — В данный момент идет выполнение.
- 267010 — Задача не будет запущена в запланированное время, потому что она отключена.
- 267011 — Запуск еще не был выполнен.
- 267012 — Для этой задачи больше нет запланированных запусков.
- 267013 — Одно или несколько свойств, необходимых для запуска этой задачи по расписанию, не были установлены.
- 267014 — Последний запуск задачи был прерван пользователем.
- 267015 — Либо у задачи нет триггеров, либо существующие триггеры отключены или не установлены.
- 2147750671 — Учетные данные повреждены.
- 2147750687 — Экземпляр этой задачи уже запущен.
- 2147943645 — Служба недоступна (установлен ли флажок «Запускать только при входе пользователя в систему»?).
- 3221225786 — Приложение было закрыто в результате нажатия CTRL + C.
- 3228369022 — Неизвестное программное исключение.
Альтернативное — вы можете открыть интерфейс планировщика и посмотреть какая ошибка отображается там (она будет текстом).
Далее вы можете создать скрипт для поиска сбойных задач. Например меня интересует только задачи со сбоями, а не успешно работающие. Так как я не знаю всех кодов, мне нужно будет исключить только коды успешного выполнения:
1 2 3 4 5 6 7 8 9 10 |
# Коды, которые меня не интересуют (успешное выполнение) $success_sc_codes = @(0, 267008, 267009, 267010, 267011, 267012) # Получает объект, который содержит детальную информацию по всем процессам $all_sc_tasks = Get-ScheduledTask | Get-ScheduledTaskInfo foreach ($task in $all_sc_tasks){ # Если код не соответствует тому что есть в массиве - выводим на экран if (!($task.LastTaskResult -in $success_sc_codes)){ $task } } |
Такой же подход можно использовать при поиске странных сервисов-программ. Например у нас есть эталонный компьютер/сервер и на нем созданы все нужные задачи. Всех их мы помещаем в один объект, а затем сравниваем с другими экземплярами:
1 2 3 4 5 6 7 8 |
# Создаем пустой массив $good_list = [System.Collections.ArrayList]@() # Получаем существующие задачи $all_sc_tasks = Get-ScheduledTask foreach ($task in $all_sc_tasks){ # Помещаем в созданный массив только имена $good_list.Add($task.TaskName) > Out-Null } |
Далее, через разные средства, мы можем сравнить этот список на других компьютерах:
1 2 3 4 5 6 7 |
# Получаем список на другом компьютере $all_sc_tasks = Get-ScheduledTask foreach ($task in $all_sc_tasks){ # Ищем имена, которые не соответствуют тому что есть в массиве if (!($task.TaskName -in $good_list)){$task } } |
Ваш комментарий будет первым