Автоматизация задач Windows через PowerShell и Task Scheduler

Зачем управлять Task Scheduler через PowerShell

Task Scheduler (Планировщик задач) — встроенный компонент Windows для автоматического выполнения скриптов и программ по расписанию или событию. Графический интерфейс удобен для единичных задач, но становится неэффективным при управлении десятками серверов. PowerShell-модуль ScheduledTasks позволяет создавать, модифицировать и мониторить задачи программно — через скрипты, в конвейерах, в DSC-конфигурациях.

Типичные сценарии автоматизации через Task Scheduler:

  • Ежедневная очистка старых логов и временных файлов
  • Перезапуск зависших служб по расписанию
  • Сбор метрик и отправка отчётов
  • Запуск скриптов при входе пользователя или запуске системы
  • Реакция на события в Event Log (аварии, блокировки)

Создание запланированных задач через PowerShell

Модуль ScheduledTasks доступен в Windows 8/Server 2012 и новее. Создание задачи состоит из трёх этапов: определение действия (Action), триггера (Trigger) и принципала (Principal).

Базовый пример: очистка логов

Создадим задачу, которая ежедневно в 03:00 удаляет логи старше 30 дней:

# Определяем действие — запуск PowerShell-скрипта
$action = New-ScheduledTaskAction `
    -Execute "powershell.exe" `
    -Argument '-NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\Clean-OldLogs.ps1"' `
    -WorkingDirectory "C:\Scripts"

# Определяем триггер — ежедневно в 03:00
$trigger = New-ScheduledTaskTrigger -Daily -At "03:00"

# Определяем принципал — от имени SYSTEM
$principal = New-ScheduledTaskPrincipal `
    -UserId "SYSTEM" `
    -LogonType ServiceAccount `
    -RunLevel Highest

# Настройки задачи
$settings = New-ScheduledTaskSettingsSet `
    -AllowStartIfOnBatteries `
    -DontStopIfGoingOnBatteries `
    -StartWhenAvailable `
    -RunOnlyIfNetworkAvailable `
    -ExecutionTimeLimit (New-TimeSpan -Hours 1) `
    -RestartCount 3 `
    -RestartInterval (New-TimeSpan -Minutes 5)

# Регистрация задачи
Register-ScheduledTask `
    -TaskName "Clean-OldLogs" `
    -TaskPath "\IT\Maintenance\" `
    -Action $action `
    -Trigger $trigger `
    -Principal $principal `
    -Settings $settings `
    -Description "Удаление логов старше 30 дней"

Параметр -TaskPath создаёт папку в планировщике для организации задач. -StartWhenAvailable обеспечивает запуск пропущенной задачи (например, если сервер был выключен в 03:00).

Скрипт очистки логов

Содержимое файла C:\Scripts\Clean-OldLogs.ps1:

# Clean-OldLogs.ps1
$logPaths = @(
    "C:\inetpub\logs\LogFiles",
    "C:\Windows\Temp",
    "D:\Apps\Logs"
)
$daysToKeep = 30
$cutoffDate = (Get-Date).AddDays(-$daysToKeep)
$totalDeleted = 0

foreach ($path in $logPaths) {
    if (Test-Path $path) {
        $files = Get-ChildItem -Path $path -Recurse -File |
            Where-Object { $_.LastWriteTime -lt $cutoffDate }
        $count = ($files | Measure-Object).Count
        $size = ($files | Measure-Object -Property Length -Sum).Sum / 1MB
        $files | Remove-Item -Force -ErrorAction SilentlyContinue
        Write-Output "$path : удалено $count файлов ($([math]::Round($size, 2)) МБ)"
        $totalDeleted += $count
    }
}

Write-Output "Итого удалено: $totalDeleted файлов"

# Запись в Event Log
New-EventLog -LogName Application -Source "LogCleanup" -ErrorAction SilentlyContinue
Write-EventLog -LogName Application -Source "LogCleanup" -EventId 1000 `
    -EntryType Information -Message "Очистка логов: удалено $totalDeleted файлов"

Типы триггеров и комбинации

PowerShell поддерживает все типы триггеров Task Scheduler: по времени, при событии, при входе пользователя, при простое системы.

Примеры различных триггеров

Различные типы триггеров для разных сценариев:

# Еженедельно — каждый понедельник и четверг в 22:00
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday,Thursday -At "22:00"

# При запуске системы (с задержкой 5 минут)
$trigger = New-ScheduledTaskTrigger -AtStartup
$trigger.Delay = 'PT5M'  # 5 минут задержки

# При входе конкретного пользователя
$trigger = New-ScheduledTaskTrigger -AtLogOn -User "DOMAIN\admin"

# Повтор каждые 15 минут в течение рабочего дня
$trigger = New-ScheduledTaskTrigger -Once -At "08:00" `
    -RepetitionInterval (New-TimeSpan -Minutes 15) `
    -RepetitionDuration (New-TimeSpan -Hours 10)

# По событию в Event Log (блокировка учётной записи)
$trigger = New-ScheduledTaskTrigger -AtLogOn  # Placeholder
$CIMTriggerClass = Get-CimClass -ClassName MSFT_TaskEventTrigger `
    -Namespace Root/Microsoft/Windows/TaskScheduler
$trigger = New-CimInstance -CimClass $CIMTriggerClass -ClientOnly
$trigger.Subscription = @"
<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4740]]</Select>
  </Query>
</QueryList>
"@
$trigger.Enabled = $true

Комбинация нескольких триггеров

Одна задача может иметь несколько триггеров:

# Задача запускается и по расписанию, и при старте системы
$triggers = @(
    (New-ScheduledTaskTrigger -Daily -At "06:00"),
    (New-ScheduledTaskTrigger -AtStartup)
)

Register-ScheduledTask `
    -TaskName "Health-Check" `
    -TaskPath "\IT\Monitoring\" `
    -Action $action `
    -Trigger $triggers `
    -Principal $principal

Управление существующими задачами

PowerShell позволяет получать информацию о задачах, изменять их параметры, запускать и останавливать.

Просмотр и фильтрация задач

Команды для работы с существующими задачами:

# Все задачи в папке
Get-ScheduledTask -TaskPath "\IT\*" | Format-Table TaskName, State, TaskPath

# Информация о конкретной задаче
Get-ScheduledTask -TaskName "Clean-OldLogs" | Get-ScheduledTaskInfo
# LastRunTime  : 08.04.2024 3:00:05
# LastTaskResult : 0  (успех)
# NextRunTime  : 09.04.2024 3:00:00

# Все задачи, которые завершились с ошибкой
Get-ScheduledTask | Get-ScheduledTaskInfo |
    Where-Object { $_.LastTaskResult -ne 0 -and $_.LastTaskResult -ne $null } |
    Select-Object TaskName, LastRunTime, LastTaskResult

# Запуск задачи вручную
Start-ScheduledTask -TaskName "Clean-OldLogs" -TaskPath "\IT\Maintenance\"

# Отключение задачи
Disable-ScheduledTask -TaskName "Clean-OldLogs" -TaskPath "\IT\Maintenance\"

# Удаление задачи
Unregister-ScheduledTask -TaskName "Clean-OldLogs" -TaskPath "\IT\Maintenance\" -Confirm:$false

Модификация параметров задачи

Изменение расписания или действия существующей задачи:

# Изменение триггера — перенос на 04:00
$newTrigger = New-ScheduledTaskTrigger -Daily -At "04:00"
Set-ScheduledTask -TaskName "Clean-OldLogs" -TaskPath "\IT\Maintenance\" -Trigger $newTrigger

# Изменение учётной записи запуска
Set-ScheduledTask -TaskName "Clean-OldLogs" -TaskPath "\IT\Maintenance\" `
    -User "DOMAIN\svc-tasks" -Password "ServicePassword123!"

# Добавление описания
$task = Get-ScheduledTask -TaskName "Clean-OldLogs" -TaskPath "\IT\Maintenance\"
$task.Description = "Удаление логов старше 30 дней. Контакт: admin@example.com"
$task | Set-ScheduledTask

Продвинутые сценарии автоматизации

Рассмотрим несколько практических сценариев, которые часто встречаются в корпоративной среде.

Мониторинг дискового пространства

Скрипт проверки свободного места с отправкой уведомления:

# Monitor-DiskSpace.ps1
$threshold = 10  # процентов
$alertRecipients = "admin@example.com"
$smtpServer = "mail.example.com"

$volumes = Get-Volume | Where-Object {
    $_.DriveLetter -and $_.DriveType -eq 'Fixed'
}

$alerts = @()
foreach ($vol in $volumes) {
    $freePercent = [math]::Round(($vol.SizeRemaining / $vol.Size) * 100, 1)
    if ($freePercent -lt $threshold) {
        $freeGB = [math]::Round($vol.SizeRemaining / 1GB, 1)
        $alerts += "Диск $($vol.DriveLetter): — $freePercent% свободно ($freeGB ГБ)"
    }
}

if ($alerts.Count -gt 0) {
    $body = "Сервер: $env:COMPUTERNAME`n`n" + ($alerts -join "`n")
    Send-MailMessage -From "monitoring@example.com" -To $alertRecipients `
        -Subject "[ALERT] Мало места на $env:COMPUTERNAME" `
        -Body $body -SmtpServer $smtpServer -Encoding UTF8
}

Перезапуск зависших служб

Скрипт для автоматического перезапуска критичных служб:

# Restart-StuckServices.ps1
$criticalServices = @("W3SVC", "MSSQLSERVER", "Spooler")
$restartedServices = @()

foreach ($svcName in $criticalServices) {
    $svc = Get-Service -Name $svcName -ErrorAction SilentlyContinue
    if ($svc -and $svc.Status -ne 'Running') {
        try {
            Restart-Service -Name $svcName -Force -ErrorAction Stop
            $restartedServices += "$svcName — перезапущен"
            Write-EventLog -LogName Application -Source "ServiceMonitor" `
                -EventId 2000 -EntryType Warning `
                -Message "Служба $svcName была перезапущена автоматически"
        } catch {
            $restartedServices += "$svcName — ОШИБКА: $($_.Exception.Message)"
        }
    }
}

if ($restartedServices.Count -gt 0) {
    # Уведомление (email или webhook)
    $body = "Перезапуск служб на $env:COMPUTERNAME :`n" + ($restartedServices -join "`n")
    Send-MailMessage -From "monitoring@example.com" -To "admin@example.com" `
        -Subject "Перезапуск служб на $env:COMPUTERNAME" `
        -Body $body -SmtpServer "mail.example.com" -Encoding UTF8
}

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

Для управления задачами на десятках серверов используйте PowerShell Remoting.

Массовое создание задач через Invoke-Command

Скрипт для развёртывания задачи на всех серверах из списка:

# Deploy-ScheduledTask.ps1
$servers = Get-Content "C:\Scripts\servers.txt"
$scriptContent = Get-Content "C:\Scripts\Clean-OldLogs.ps1" -Raw

Invoke-Command -ComputerName $servers -ScriptBlock {
    param($script)

    # Копируем скрипт на целевой сервер
    $scriptPath = "C:\Scripts\Clean-OldLogs.ps1"
    if (-not (Test-Path "C:\Scripts")) { New-Item -Path "C:\Scripts" -ItemType Directory }
    Set-Content -Path $scriptPath -Value $script -Encoding UTF8

    # Создаём задачу
    $action = New-ScheduledTaskAction -Execute "powershell.exe" `
        -Argument "-NoProfile -ExecutionPolicy Bypass -File $scriptPath"
    $trigger = New-ScheduledTaskTrigger -Daily -At "03:00"
    $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
    $settings = New-ScheduledTaskSettingsSet -StartWhenAvailable

    # Удаляем существующую задачу если есть
    Unregister-ScheduledTask -TaskName "Clean-OldLogs" -TaskPath "\IT\Maintenance\" `
        -Confirm:$false -ErrorAction SilentlyContinue

    Register-ScheduledTask -TaskName "Clean-OldLogs" -TaskPath "\IT\Maintenance\" `
        -Action $action -Trigger $trigger -Principal $principal -Settings $settings

    Write-Output "$env:COMPUTERNAME : задача создана"
} -ArgumentList $scriptContent

Мониторинг и отчёты по задачам

Для контроля выполнения задач на нескольких серверах создайте централизованный отчёт.

Скрипт сбора статуса задач

Скрипт собирает статус всех задач из папки \IT\ со всех серверов:

# Get-TaskReport.ps1
$servers = Get-Content "C:\Scripts\servers.txt"

$report = Invoke-Command -ComputerName $servers -ScriptBlock {
    Get-ScheduledTask -TaskPath "\IT\*" | ForEach-Object {
        $info = $_ | Get-ScheduledTaskInfo
        [PSCustomObject]@{
            Server       = $env:COMPUTERNAME
            TaskName     = $_.TaskName
            State        = $_.State
            LastRun      = $info.LastRunTime
            LastResult   = $info.LastTaskResult
            NextRun      = $info.NextRunTime
            ResultText   = if ($info.LastTaskResult -eq 0) { "OK" } else { "ERROR" }
        }
    }
}

# Фильтр: только ошибки
$errors = $report | Where-Object { $_.LastResult -ne 0 }
if ($errors) {
    $errors | Format-Table Server, TaskName, LastRun, LastResult -AutoSize
}

# Экспорт в CSV
$report | Export-Csv -Path "C:\Reports\TaskReport_$(Get-Date -Format yyyyMMdd).csv" `
    -NoTypeInformation -Encoding UTF8

Часто задаваемые вопросы

Используйте параметры -User и -Password при регистрации: Register-ScheduledTask ... -User "DOMAIN\svc-user" -Password "Pass123!". Учётная запись должна иметь право «Log on as a batch job» (настраивается через Local Security Policy → User Rights Assignment). Для SYSTEM-аккаунта пароль не требуется.

Код 0x1 означает «Incorrect function» — обычно ошибка в пути к исполняемому файлу или аргументах. Проверьте: путь к powershell.exe указан полностью, аргумент -File содержит корректный путь к скрипту в кавычках, скрипт существует и не имеет синтаксических ошибок. Для диагностики добавьте в скрипт логирование: Start-Transcript -Path C:\Logs\task.log.

Да, Group Policy Preferences (Computer Configuration → Preferences → Control Panel Settings → Scheduled Tasks) позволяет создавать задачи через GPO. Однако GPP-задачи ограничены: нет поддержки всех типов триггеров, сложно передавать параметры. Для сложных сценариев рекомендуется PowerShell-скрипт, запускаемый через GPO Startup Script.

Включите аудит через Group Policy: Computer Configuration → Policies → Windows Settings → Security Settings → Advanced Audit Policy → Object Access → Audit Other Object Access Events. После этого изменения задач фиксируются в Event Log (Security) с Event ID 4698 (создание), 4699 (удаление), 4702 (изменение). В событии указан пользователь, имя задачи и содержимое XML-конфигурации.

Нужна помощь с настройкой?

Специалисты АйТи Фреш помогут с внедрением и настройкой — 15+ лет опыта, обслуживание от 15 000 ₽/мес

📞 Связаться с нами
#PowerShell Task Scheduler#запланированные задачи Windows#автоматизация PowerShell#New-ScheduledTask#планировщик задач#скрипты по расписанию#Windows автоматизация#ScheduledTasks модуль
Комментарии 0

Оставить комментарий

загрузка...