· 16 мин чтения

Планировщик задач и PowerShell в Windows: автоматизация рутины админа

Меня зовут Семёнов Евгений Сергеевич, директор АйТи Фреш. За 15 лет Windows-администрирования я собрал гигабайт скриптов, которые работают ночью, пока IT-отдел спит: крутят бэкапы, шлют отчёты, чистят временные папки, собирают инвентарь. Планировщик задач + PowerShell — это пара инструментов, без которых полноценную эксплуатацию Windows-инфраструктуры не построишь. Разберём правильные подходы, триггеры, сервисные учётки и типичные грабли.

Почему не использовать schtasks.exe

Schtasks появился в NT4, синтаксис у него такой же замшелый. В современных версиях Windows Server есть модуль ScheduledTasks с объектной моделью, версионностью, экспортом-импортом и поддержкой PowerShell Remoting. Я всегда использую его — код читается, переносится, автоматизируется.

Четыре компонента задачи

КомпонентКомандаЧто делает
ActionNew-ScheduledTaskActionЧто запускаем
TriggerNew-ScheduledTaskTriggerКогда запускаем
PrincipalNew-ScheduledTaskPrincipalПод какой учёткой
SettingsNew-ScheduledTaskSettingsSetКак ведёт себя

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

$action = New-ScheduledTaskAction -Execute 'powershell.exe' `
  -Argument '-NoProfile -ExecutionPolicy Bypass -File C:\Scripts\Backup-UserData.ps1' `
  -WorkingDirectory 'C:\Scripts'

$trigger = New-ScheduledTaskTrigger -Daily -At 2:30am

$principal = New-ScheduledTaskPrincipal -UserId 'CORP\svc_backup' `
  -LogonType Password -RunLevel Highest

$settings = New-ScheduledTaskSettingsSet `
  -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries `
  -StartWhenAvailable -RunOnlyIfNetworkAvailable `
  -ExecutionTimeLimit (New-TimeSpan -Hours 4)

Register-ScheduledTask -TaskName 'Daily-User-Backup' `
  -Description 'Бэкап домашних каталогов в 02:30' `
  -Action $action -Trigger $trigger -Principal $principal -Settings $settings `
  -Password (Read-Host -AsSecureString)

Скрипт с правильным логированием

# C:\Scripts\Backup-UserData.ps1
[CmdletBinding()]
param(
    [string]$Source   = 'D:\Users',
    [string]$Dest     = '\\nas01\Backups\Users',
    [int]   $RetentionDays = 30
)

$ErrorActionPreference = 'Stop'
$log = "C:\Logs\Backup-$(Get-Date -f yyyyMMdd).log"
Start-Transcript -Path $log -Append

try {
    Write-Host "[$(Get-Date)] Start backup $Source -> $Dest"
    robocopy $Source $Dest /MIR /MT:8 /R:2 /W:5 /LOG+:$log
    if ($LASTEXITCODE -gt 7) { throw "Robocopy exit $LASTEXITCODE" }

    # Удаление старых
    Get-ChildItem $Dest -Directory |
      Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$RetentionDays) } |
      Remove-Item -Recurse -Force

    Write-Host "[$(Get-Date)] Backup OK"
}
catch {
    Write-Error $_
    # Alert
    $body = @{ text = "Backup FAIL: $_" } | ConvertTo-Json
    Invoke-RestMethod -Uri $env:TEAMS_WEBHOOK -Method Post -Body $body -ContentType 'application/json'
    exit 1
}
finally {
    Stop-Transcript
}

Триггеры: от простых до событийных

Task Scheduler умеет запускать по времени, по логину пользователя, при старте системы, при простое, при событии журнала. Я регулярно использую все пять типов.

# Каждые 5 минут
$t1 = New-ScheduledTaskTrigger -Once -At (Get-Date) `
  -RepetitionInterval (New-TimeSpan -Minutes 5) `
  -RepetitionDuration (New-TimeSpan -Days 365)

# При появлении события 4625 (неудачный вход) в Security log
$xml = @'
<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4625]]</Select>
  </Query>
</QueryList>
'@
$class  = Get-CimClass -Namespace Root/Microsoft/Windows/TaskScheduler `
  -ClassName MSFT_TaskEventTrigger
$t2 = New-CimInstance -CimClass $class -Property @{ Enabled=$true; Subscription=$xml } `
  -ClientOnly

Сервисные учётки: принципы

Я всегда соблюдаю правило: одна задача — одна учётка. Общие сервисные аккаунты с правами Domain Admin — прямой путь к инциденту. Для каждой задачи создаётся выделенный svc_-аккаунт с минимальным набором прав.

Использование gMSA

# Создание gMSA
New-ADServiceAccount -Name gMSA-backup -DNSHostName backup.corp.local `
  -PrincipalsAllowedToRetrieveManagedPassword "Backup-Servers"

# На целевом сервере
Install-ADServiceAccount -Identity gMSA-backup
Test-ADServiceAccount -Identity gMSA-backup

# Регистрация задачи под gMSA
$principal = New-ScheduledTaskPrincipal -UserId 'CORP\gMSA-backup$' -LogonType Password
Register-ScheduledTask -TaskName 'BackupWithGMSA' `
  -Action $action -Trigger $trigger -Principal $principal -Settings $settings

Экспорт и массовое развёртывание

У нас на практике пять однотипных серверов получают одну и ту же задачу. Экспортируем XML — и раскатываем через PowerShell Remoting.

# Экспорт
Export-ScheduledTask -TaskName 'Daily-User-Backup' | Out-File 'C:\Tasks\backup.xml'

# Импорт на другом сервере
$xml = Get-Content 'C:\Tasks\backup.xml' -Raw
Register-ScheduledTask -Xml $xml -TaskName 'Daily-User-Backup' -User 'CORP\svc_backup' -Password $pwd

Мини-кейс: клиника, 14 серверов

В январе 2025 года к нам обратилась медицинская клиника — 14 Windows-серверов, сеть 40G Mellanox, хранилище на Dell Xeon Platinum 8280 в дата-центре МТС. Задача: централизованно автоматизировать 7 рутин на всех серверах — бэкап конфигов, очистка temp, отчёт о дисковом пространстве, перезапуск 1С-служб в 3 часа ночи, инвентарь ПО, ротация логов, проверка статуса антивируса. За два дня мы написали 7 PowerShell-скриптов с едиными шаблонами логирования, упаковали их в DSC-модуль и раскатали через Ansible-for-Windows. Единая точка — gMSA, единый формат логов в C:\Logs, алерты в Teams при exit ≠ 0. Стоимость работ — 48 000 руб., экономия для IT-отдела — около 8 часов/неделю ручной рутины.

Диагностика не сработавших задач

# История задачи
Get-ScheduledTask -TaskName 'Daily-User-Backup' | Get-ScheduledTaskInfo

# Последние результаты из журнала
Get-WinEvent -LogName 'Microsoft-Windows-TaskScheduler/Operational' -MaxEvents 50 |
  Where-Object { $_.Message -like '*Daily-User-Backup*' }

# Ручной запуск
Start-ScheduledTask -TaskName 'Daily-User-Backup'

Типичные ошибки

Автоматизируем рутину Windows-админа

PowerShell-скрипты, Task Scheduler, gMSA, централизованное логирование и алерты. От 25 000 руб. за пакет из 5 типовых задач на 3–10 серверов.

Телефон: +7 903 729-62-41
Telegram: @ITfresh_Boss
Семёнов Евгений Сергеевич, директор АйТи Фреш

FAQ — частые вопросы по Task Scheduler + PowerShell

Чем Register-ScheduledTask отличается от schtasks.exe?
Register-ScheduledTask — современный командлет PowerShell с объектной моделью. Schtasks.exe — старый CLI.
Под какой учёткой запускать задачи?
Для системных — SYSTEM. Для доменных — выделенная сервисная учётка с минимальными правами.
Как обрабатывать ошибки в скрипте?
try/catch, логирование через Start-Transcript, алерты через webhook.
Можно ли запускать PS-скрипт без окна консоли?
Да, параметр -WindowStyle Hidden и чекбокс 'Run whether user is logged on or not'.
Поддерживает ли Task Scheduler триггеры по событиям?
Да, триггер OnEvent с XPath-запросом по журналу.

Подпишитесь на рассылку ITfresh

Раз в неделю — практические гайды для руководителя IT и сисадмина: безопасность, 1С, миграции, резервные копии, лайфхаки из реальных проектов.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.