Используем Powershell для работы с планировщиком заданий для создания и изменения задач


18 декабря 2020


Создаем задачи в планировщике с Powershell изменяем и запускаем их

В Windows есть механизм под названием 'Планировщик заданий' (Task Scheduler). Основная задача планировщика - выполнение задач в определенный момент времени или при определенном действии. В этой статье будет рассмотрены варианты работы с ним через Powershell. На примере мы создадим задание в виде скрипта с Powershell, изменим и удалим его используя только команды.

 

Работа планировщика в Powershell

Отличительной чертой работы Powershell является то, что мы должны создать каждый из объектов (результат команд) планировщика отдельно, а затем объединить их с помощью 1 команды. Сами объекты делятся на следующие:

  1. Action (Действие) - определяет что мы должны запустить. Действия проявляются как программа (например браузер) с аргументами (открыть определенный сайт). В одной задаче может быть до 32 действий;
  2. Trigger (Триггер) - это событие при котором должно запуститься действие. Событие может быть привязано к времени или каким-то процессом в системе (включение компьютера, вход пользователя и т.д.). Время можно устанавливать как определенное, например в 14:00, так и интервальное - каждые 2 часа. Так же как и действий триггеров может быть несколько.
  3. Settings (Настройки) - дополнительные условия обработки задач. Это может быть перезапуск в случае сбоя задачи или самоудаление если задача не используется.
  4. Security Options (Параметры безопасности) - определяют привилегии и пользователя от имени которого будут запущены задания.

Планировщик задач Windows

3 и 4 пункт не является обязательными при создании задачи т.к. уже имеет настройки по умолчанию.

За создание задач в планировщике отвечает модуль ScheduledTasks, который имеет следующие команды:

Get-Command -Module ScheduledTasks

Создание скрипта для тестирования

Что бы продемонстрировать работу планировщика я создам скрипт, который будет сохранять логи с журнала Windows в папку 'logs'. Ниже находится сам скрипт:

# Папка с логами
$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

Скрипт сбора логов и сохранения в XML

Команды выше не должны выдавать каких либо ошибок. Ошибка может быть, например, с несуществующей папкой 'logs'. Сам скрипт я сохранил по пути 'C:\scheduler_task.ps1'. Его запуск не выдает каких-то ошибок:

.\scheduler_task.ps1

Пример работы скрипта сбора логов и сохранения в XML

У вас так же будет создан файл в папке 'logs'.

 

Создание выполняемого действия для планировщика

Для создания 'action' мы должны указать программу и аргументы. В качестве программы будет сам интерпретатор 'powershell.exe', а аргументом будет путь до скрипта. Как говорилось раньше у нас будет несколько объектов (результат команд) и все их нужно будет объединить. Что бы это было возможным мы должны поместить результаты работы в переменные:

$task_action = New-ScheduledTaskAction `
    -Execute 'powershell.exe' `
    -Argument '-File C:\scheduler_task.ps1'

Создание действия в Powershell для планировщика задач

Мы так же можем указать параметр 'WorkingDirectory', который определяет откуда и будет запущена программа. Учитывая, что 'powershell.exe' виден через системные переменные использовать параметр 'WorkingDirectory' нам не требуется.

Действия выше аналогичны следующим настройкам в интерфейсе (т.е. так мы обычно добавляем скрипт Powershell в планировщик):

Создание задачи в планировщике для работы скрипта 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:

$task_trigger = New-ScheduledTaskTrigger -Once -At 13:00

Создание триггера в Powershell для планировщика задач

Еще несколько примеров:

# Ежедневно в 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'. В этой команде определим сам интервал:

$time = New-TimeSpan -Minutes 5
$task_trigger = New-ScheduledTaskTrigger -Once -At 0:00 -RepetitionInterval $time

Создание триггера в Powershell для планировщика задач с повторением

 

Регистрация задачи в планировщике

Теперь, после выполнения минимальных требований в виде 'action' и 'trigger', мы должны объединить эти объекты. Это делается с помощью команды 'Register-ScheduledTask'. Дополнительно мы можем определить название и описание создаваемого объекта:

$name = 'Сбор логов'
$description = 'Сбор логов приложений каждые 5 минут в папку c:\logs'

Register-ScheduledTask -TaskName $name `
   -Description $description `
   -Action $task_action `
   -Trigger $task_trigger

Регистрация задачи для планировщика с помощью Powershell

Учитывайте, что вы можете использовать несколько триггеров  и действий. Для этого вы должны перечислить их через запятую.

TaskPath указывает где была создана задача. В примере выше это произошло в корне планировщика:

Просмотр задач в планировщике Windows

Вы можете использовать аналогичный параметр для регистрации задачи в другой директории:

Register-ScheduledTask -TaskName 'SomeTask' `
   -TaskPath '\Microsoft' `
   -Action $action1,$action2 `
   -Trigger $trigger1,$trigger2

Регистрация и создание задачи в планировщике Windows с Powershell

Способа узнать путь два:

  1. Через графический интерфейс;
  2. Через команду 'Get-ScheduledTask' (будет рассмотрена ниже).

В powershell есть еще одна команда, которая может участвовать в создании задач "New-ScheduledTask". Основное отличие такой команды в том, она не регистрирует (добавляет) задачу в сервис планировщика. Если бы мы использовали обе команды это бы выглядело так:

# Объединение объектов
$task = New-ScheduledTask -Action $action1,$action2 `
       -Trigger $trigger1,$trigger2

# Их активация
Register-ScheduledTask -TaskName 'SomeTask' `
                      -TaskPath '\Microsoft' `
                      -InputObject $task

 

Запуск и получение дополнительной информации

Для запуска задачи, не зависимо от триггеров, используется команда 'Start-ScheduledTask':

Start-ScheduledTask -TaskName 'Сбор логов'

Запуск задачи планировщика с Powershell

У нас так же есть 2 команды, которые возвращают информацию о задачах.

Первая команда просто возвращает список задач, которые есть в каталогах планировщика их статус и путь:

Get-ScheduledTask

Получение задач планировщика с PowershellУ команды запуска и получения задач из планировщика можно использовать параметры:

  • TaskName - имя объекта;
  • TaskPath - путь до объекта.
Get-ScheduledTask -TaskPath '\'

Более полезная команда следующая, так как вернет немного больше информации:

Get-ScheduledTaskInfo -TaskName 'Сбор логов'

Получение информации о задаче планировщика с Powershell

Само собой все эти команды можно использовать в конвейере:

Get-ScheduledTask -TaskName 'Сбор логов' | Start-ScheduledTask

Если задача занимает много времени и ее нужно остановить - можно выполнить следующие действия:

Stop-ScheduledTask 'Сбор логов'

 

Изменение пользователя, параметров безопасности и уровня запуска

Создавая задачи в планировщике мы имеем блок 'Security Options', который чаще используется с настройками по умолчанию. В этом блоке определяются следующие параметры:

  • Пользователь, от имени которого будет выполнен запуск;
  • Выполняется ли задача для вошедших в систему пользователей;
  • Привилегии запуска (от пользователя/администратора);
  • Совместимость.

В графическом интерфейсе эти параметры настраиваются в следующем блоке:

Выполнение задачи планировщика для пользователей вошедших в систему

Так же как и в случае с созданием задачи, в случае ее изменения мы создаем разные объекты (результаты команд), которые затем привязываем через команду 'Set-SchedukedTask'.

С помощью следующих команд мы изменим пользователя, повысим права и изменим совместимость:

# Изменяем пользователя и повышаем права запуска
$task_user = New-ScheduledTaskPrincipal -UserId '.\admin' -RunLevel Highest
# Изменяем совместимость
$task_settings = New-ScheduledTaskSettingsSet -Compatibility 'Win8'
# Добавляем объекты созданные выше к существующей задаче
Set-ScheduledTask -TaskName 'Сбор логов' -Principal $task_user -Settings $task_settings

Использование совместимости и другого пользователя в планировщике задач с Powershell

Если у вас будет следующая ошибка, то скорее всего она связана с неверным пользователем:

  • Set-ScheduledTask : No mapping between account names and security IDs was done.

Само собой эти же объекты можно использовать при создании (регистрации) задачи в планировщике:

$name = 'Task 3'

Register-ScheduledTask -TaskName $name `
   -Action $task_action `
   -Trigger $task_trigger `
   -Principal $task_user `
   -Settings $task_settings

Учитывайте, что у New-ScheduledTaskSettingsSet около 30 возможных параметров (работа при отключенной батареи, максимальное количество перезапусков и т.д.). В примере выше рассмотрено лишь несколько.

Изменение триггеров и действий

С помощью Set-ScheduledTask так же добавляются и изменяются триггеры и действия. Изменение будут заключаться в полной замене существующих триггеров и действий у задач. Вам просто нужно создать объект по аналогии с тем, как это делалось в предыдущих разделах:

$trigger = New-ScheduledTaskTrigger -Daily -At 14:00
$action = New-ScheduledTaskAction -Execute Calc.exe

Set-ScheduledTask -TaskName 'Сбор логов' -Action $action -trigger $trigger

Запуск задачи в определенное время с Powershell 

 

Бэкап, удаление и восстановление задач планировщика с Powershell

Удобной возможностью использования Powershell является импорт и экспорт задач планировщика. По сути вы можете создать шаблон, который можно использовать на разных компьютерах без особой работы с кодом. По умолчанию, сам Powershell, не предоставляет прямой возможности бэкапа и восстановления, но это можно сделать через другие команды.

Резервное копирование

Для бэкапа мы можем использовать команду Export-CliXml. Для этого нам нужно будет получить задачу и использовать конвейер:

Get-ScheduledTask -TaskName 'Сбор логов' | Export-Clixml 'C:\LogTaskBackup.xml'

Резервное копирование задач планировщика с Powershell

Для экспорта в Powershell так же есть 'Export-ScheduledTask', но нет аналогичной команды импорта. Что бы импортировать такие файлы-задачи мы можем использовать только GUI. Из-за этого она не приведена в примере выше. 

Удаление, отключение и включение

При удалении задачи, по умолчанию, запрашивается подтверждение. Что бы этого не было добавляется ключ 'Confirm':

Unregister-ScheduledTask -TaskName 'Сбор логов' -Confirm:$False

Удаление задачи планировщика с Powershell

Если требуется только отключить задачу используйте Disable:

Disable-ScheduledTask -TaskName 'Сбор логов'

Включение:

Enable-ScheduledTask -TaskName 'Сбор логов'

Восстановление

Восстановление выполняется в несколько шагов. Первое - мы должны выполнить импорт XML документа в Powershell:

$task = Import-Clixml -Path 'C:\LogTaskBackup.xml'

На одном из сайтов я прочитал, что следующий параметр нужно изменять на "Interactive", так как без него не будет работать задача, но у меня этот параметр не изменялся при экспорте:

$task.Principal

Изменение параметра входа пользователей для планировщика с Powershell

Этот параметр связан со входом пользователя через GUI. Аналогичное название в интерфейсе планировщика задач "Выполнять только для пользователей, вошедших в систему". Если этот параметр у вас отличается - вы сможете изменить его так:

$task.Principal.LogonType = 'Interactive'

Далее нам нужно зарегистрировать эту задачу определяя каждый из параметров отдельно:

Register-ScheduledTask `
   -TaskName $task.TaskName `
   -Action $task.Actions `
   -Trigger $task.Triggers `
   -Settings $task.Settings `
   -Principal $task.Principal `
   -User 'administrator' `
   -Password '123'

Восстановление бэкапа планировщика задач Powershell

 

Анализ выполнения и завершения, а так же сравнение

Используя предыдущие команды мы можем выполнить некоторую автоматизацию. Например так мы можем увидеть результат выполненных задач:

Get-ScheduledTask | Get-ScheduledTaskInfo | select *

Получение результата выполненной задачи планировщика

Часть этих кодов имеет следующую расшифровку (был использован автоматический переводчик):

  • 0 - операция успешно завершена.
  • 1 - Вызывается неправильная функция или неизвестная функция. 2 Файл не найден.
  • 10 - Неправильная среда.
  • 267008 - Задача готова к запуску в следующее запланированное время.
  • 267009 - В данный момент идет выполнение.
  • 267010 - Задача не будет запущена в запланированное время, потому что она отключена.
  • 267011 - Запуск еще не был выполнен.
  • 267012 - Для этой задачи больше нет запланированных запусков.
  • 267013 - Одно или несколько свойств, необходимых для запуска этой задачи по расписанию, не были установлены.
  • 267014 - Последний запуск задачи был прерван пользователем.
  • 267015 - Либо у задачи нет триггеров, либо существующие триггеры отключены или не установлены.
  • 2147750671 - Учетные данные повреждены.
  • 2147750687 - Экземпляр этой задачи уже запущен.
  • 2147943645 - Служба недоступна (установлен ли флажок «Запускать только при входе пользователя в систему»?).
  • 3221225786 - Приложение было закрыто в результате нажатия CTRL + C.
  • 3228369022 - Неизвестное программное исключение.

Альтернативное - вы можете открыть интерфейс планировщика и посмотреть какая ошибка отображается там (она будет текстом). 

Получение результата выполненной задачи планировщика в GUI

Далее вы можете создать скрипт для поиска сбойных задач. Например меня интересует только задачи со сбоями, а не успешно работающие. Так как я не знаю всех кодов, мне нужно будет исключить только коды успешного выполнения:

# Коды, которые меня не интересуют (успешное выполнение)
$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
   }
}

Поиск ошибок в планировщике задач

Такой же подход можно использовать при поиске странных сервисов-программ. Например у нас есть эталонный компьютер/сервер и на нем созданы все нужные задачи. Всех их мы помещаем в один объект, а затем сравниваем с другими экземплярами:

# Создаем пустой массив
$good_list = [System.Collections.ArrayList]@()
# Получаем существующие задачи
$all_sc_tasks = Get-ScheduledTask
foreach ($task in $all_sc_tasks){
   # Помещаем в созданный массив только имена
   $good_list.Add($task.TaskName) > Out-Null
}

Получение имен задач планировщика с Powershell

Далее, через разные средства, мы можем сравнить этот список на других компьютерах:

# Получаем список на другом компьютере
$all_sc_tasks = Get-ScheduledTask
foreach ($task in $all_sc_tasks){
   # Ищем имена, которые не соответствуют тому что есть в массиве
   if (!($task.TaskName -in $good_list)){
       $task
   }
}

Поиск устаревших задач планировщика с Powershell

...

Теги: #powershell


Популярные тэги
О блоге
Этот блог представляет собой конспекты выученного материала, преобретенного опыта и лучшие практики в системном администрировании и программировании.