· 16 мин чтения

PowerShell-скрипты, которые экономят моему отделу 8 часов в неделю

Я Семёнов Евгений Сергеевич, директор АйТи Фреш. За 15+ лет обслуживания корпоративных сетей мы выжали из PowerShell максимум, и сегодня у нас в отделе есть папка Scripts с 180 рабочими инструментами. Эта статья — выжимка самых ходовых скриптов, которые я пишу почти на каждом новом клиенте в первый же месяц. Отчёты по AD, инвентаризация железа, мониторинг дисков, проверка антивируса и служб — всё то, что без автоматизации отнимает часы ручной работы.

Базовая настройка рабочего окружения

Прежде чем писать полезные скрипты, подготовьте среду. VS Code с расширением PowerShell — стандарт де-факто. Установите PSReadLine последней версии, psake или Invoke-Build для тасков, Pester для тестов. Модули, без которых я не работаю:

МодульНазначениеКоманда установки
ActiveDirectoryРабота с пользователями, группами, компьютерами ADRSAT: Install-WindowsFeature RSAT-AD-PowerShell
ImportExcelЧтение/запись XLSX без установленного ExcelInstall-Module ImportExcel -Scope CurrentUser
PSWindowsUpdateУправление Windows Update удалённоInstall-Module PSWindowsUpdate
SecretManagementХранение паролей в защищённом хранилищеInstall-Module Microsoft.PowerShell.SecretManagement
dbatoolsВсё для SQL ServerInstall-Module dbatools
PSFrameworkЛогирование, конфигурация, работа со временемInstall-Module PSFramework

Все скрипты я храню в C:\Scripts\ с раздельными подпапками: Reports, Maintenance, Incidents, Scheduled. Версионирую в Git (локальный репо или корпоративный GitLab), чтобы откатить, если что-то пошло не так.

Отчёт по Active Directory: еженедельная рассылка

Стандартная задача: HR требует раз в неделю список уволенных учёток, которые ещё включены. Бухгалтерия хочет знать, кто не заходил месяц. Менеджеры — список участников своих групп. У нас на практике автоматизация этих трёх отчётов освободила младшему админу 6 часов в неделю.

function Get-StaleADUsers {
    [CmdletBinding()]
    param(
        [int]$DaysInactive = 90,
        [string]$ReportPath = "C:\Scripts\Reports\stale-users-$(Get-Date -f yyyyMMdd).xlsx"
    )
    $cutoff = (Get-Date).AddDays(-$DaysInactive)
    $users = Get-ADUser -Filter { Enabled -eq $true } `
        -Properties LastLogonTimestamp, Department, Manager, whenCreated |
        Where-Object {
            $_.LastLogonTimestamp -and
            [DateTime]::FromFileTime($_.LastLogonTimestamp) -lt $cutoff
        } | Select-Object Name, SamAccountName, Department,
            @{N='LastLogon';E={[DateTime]::FromFileTime($_.LastLogonTimestamp)}},
            whenCreated
    $users | Export-Excel -Path $ReportPath -AutoSize -TableName StaleUsers
    Write-Output "Найдено $($users.Count) учёток старше $DaysInactive дней"
    return $ReportPath
}

$file = Get-StaleADUsers -DaysInactive 60
Send-MailMessage -From 'reports@itfresh.local' -To 'hr@itfresh.local' `
    -Subject "AD: неактивные учётки (60 дней)" `
    -Body "Отчёт во вложении." -Attachments $file `
    -SmtpServer mail.itfresh.local -UseSsl

Скрипт запускается по расписанию каждый понедельник в 08:00. HR получает XLSX со всеми полями, сортирует, отмечает и присылает список на отключение. Весь процесс — час в неделю вместо прежнего дня.

Инвентаризация рабочих станций

Когда клиент спрашивает «сколько у нас ПК и какая на них оперативка» — я вытаскиваю файл, который собирает эти данные каждую ночь. Скрипт запускается через scheduled task, опрашивает WMI на всех машинах домена и складывает результат в CSV:

$computers = Get-ADComputer -Filter { Enabled -eq $true -and OperatingSystem -like '*Windows*' }
$report = foreach ($c in $computers) {
    $name = $c.DNSHostName
    try {
        $os = Get-CimInstance Win32_OperatingSystem -ComputerName $name -ErrorAction Stop
        $cs = Get-CimInstance Win32_ComputerSystem -ComputerName $name
        $cpu = Get-CimInstance Win32_Processor -ComputerName $name | Select-Object -First 1
        $disk = Get-CimInstance Win32_LogicalDisk -ComputerName $name -Filter "DeviceID='C:'"
        [PSCustomObject]@{
            Host      = $name
            OS        = $os.Caption
            Build     = $os.BuildNumber
            Uptime    = (Get-Date) - $os.LastBootUpTime
            CPU       = $cpu.Name
            RAM_GB    = [math]::Round($cs.TotalPhysicalMemory / 1GB, 1)
            C_Free_GB = [math]::Round($disk.FreeSpace / 1GB, 1)
            LastUser  = $cs.UserName
            Status    = 'OK'
        }
    } catch {
        [PSCustomObject]@{ Host=$name; Status="Unreachable: $($_.Exception.Message.Substring(0,60))" }
    }
}
$report | Export-Csv -Path "C:\Scripts\Reports\inventory-$(Get-Date -f yyyyMMdd).csv" `
    -NoTypeInformation -Encoding UTF8

На сети из 150 машин скрипт отрабатывает минут за 5, если все доступны. Для ускорения оборачиваю в Invoke-Parallel или ForEach-Object -Parallel (PS 7+) — получаю результат за 50 секунд.

Мониторинг дисков серверов

Один из самых ценных скриптов. Опрашивает все серверы через WMI и шлёт алерт в Telegram (или на почту), если на каком-то разделе меньше 10% свободного места:

$servers = Get-ADComputer -Filter { OperatingSystem -like '*Server*' } | Select-Object -ExpandProperty DNSHostName
$alerts = @()
foreach ($srv in $servers) {
    $disks = Get-CimInstance Win32_LogicalDisk -ComputerName $srv -Filter "DriveType=3" -ErrorAction SilentlyContinue
    foreach ($d in $disks) {
        $pct = [math]::Round(100 * $d.FreeSpace / $d.Size, 1)
        if ($pct -lt 10) {
            $alerts += "$srv $($d.DeviceID) — свободно ${pct}% ($([math]::Round($d.FreeSpace/1GB,1)) ГБ)"
        }
    }
}
if ($alerts) {
    $msg = "Низкий остаток места:`n" + ($alerts -join "`n")
    $token = Get-Secret -Name TelegramBot -AsPlainText
    $chatId = '-100123456789'
    Invoke-RestMethod -Uri "https://api.telegram.org/bot$token/sendMessage" -Method Post `
        -Body @{ chat_id = $chatId; text = $msg }
}

Настраиваю запуск каждые 30 минут. На одном из клиентов — логистика, 18 серверов, в том числе СХД — этот скрипт в декабре 2025 за три дня поймал три переполнения: забились логи IIS, перестал ротироваться бэкап и запустился runaway-процесс 1С. Все три случая разрулили до того, как сервис встал.

Проверка Windows Defender на всех ПК

Скрипт, который я запускаю раз в день на клиенте из поста «антивирус устарел на половине машин»:

$report = Get-ADComputer -Filter { Enabled -eq $true -and OperatingSystem -like '*Windows*' } |
    ForEach-Object {
        $name = $_.DNSHostName
        try {
            $av = Invoke-Command -ComputerName $name -ScriptBlock {
                Get-MpComputerStatus | Select-Object AntivirusEnabled,
                    RealTimeProtectionEnabled, AntispywareSignatureLastUpdated,
                    AntispywareSignatureVersion, QuickScanAge
            } -ErrorAction Stop
            [PSCustomObject]@{
                Host = $name
                AV = $av.AntivirusEnabled
                RT = $av.RealTimeProtectionEnabled
                SigAge_h = [math]::Round(((Get-Date)-$av.AntispywareSignatureLastUpdated).TotalHours,1)
                ScanAge_h = $av.QuickScanAge
            }
        } catch { [PSCustomObject]@{ Host=$name; Error=$_.Exception.Message.Substring(0,50) } }
    }
$report | Where-Object { $_.AV -eq $false -or $_.SigAge_h -gt 48 } |
    Export-Excel -Path "C:\Scripts\Reports\av-status-$(Get-Date -f yyyyMMdd).xlsx" -AutoSize

Мини-кейс: автоматизация отдела поддержки

В марте 2025 зашёл к клиенту — торговая компания, 90 рабочих мест. У них один помощник администратора тратил половину рабочего дня на рутину: проверка учёток новых сотрудников, разблокировка заблокированных учёток, отчёт по истёкшим паролям, генерация временных паролей для сотрудников, которые забыли пароль. Я за две недели написал им набор из 11 скриптов и чат-бот в Telegram, который эти скрипты дёргает.

Сервер для автоматизации — обычный Dell PowerEdge R740 с Xeon, 64 ГБ RAM, подключённый на 40G Mellanox к файлсерверу. Скрипты разворачивают новую учётку за 4 секунды, формируют инструкцию и письмо HR, создают папку на файловом сервере. Было 20 минут ручной работы на одну учётку — стало 15 секунд на нажатие кнопки в боте. Экономия составила около 4,5 часов в неделю, что освободило помощника для реальной технической работы.

Автоматический запуск скриптов

Скрипт, который не запускается сам — не скрипт, а черновик. Варианты:

# Пример регистрации задачи
$action = New-ScheduledTaskAction -Execute 'powershell.exe' `
    -Argument '-NoProfile -ExecutionPolicy Bypass -File C:\Scripts\Reports\Daily-AD.ps1'
$trigger = New-ScheduledTaskTrigger -Daily -At 7:30am
$principal = New-ScheduledTaskPrincipal -UserId 'ITFRESH\svc_scripts' `
    -LogonType Password -RunLevel Highest
Register-ScheduledTask -TaskName 'Daily-AD-Report' -Action $action `
    -Trigger $trigger -Principal $principal `
    -Description 'Ежедневный отчёт по неактивным AD-учёткам'

Логирование и мониторинг работы скриптов

Без логов у вас скрипты, которые «вроде работают». Минимум:

# Универсальная обёртка для любых скриптов
Start-Transcript -Path "C:\Scripts\Logs\$(Split-Path -Leaf $PSCommandPath)-$(Get-Date -f yyyyMMdd).log" -Append
try {
    # ваш код
} catch {
    $err = $_.Exception.Message
    Write-EventLog -LogName Application -Source 'PS-Scripts' -EntryType Error `
        -EventId 1001 -Message "Script failed: $err"
    throw
} finally { Stop-Transcript }

Автоматизируем админку вашего офиса

Напишу PowerShell-инструменты под ваши задачи: отчёты, ежедневный мониторинг, онбординг/оффбординг, интеграции с 1С и CRM. Опыт 15+ лет, от офисов 10 ПК до производств на 800 рабочих мест. Серверы на Xeon Platinum 8280, дата-центр МТС с 40G uplink — если нужна выделенная инфраструктура для автоматизации.

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

FAQ — частые вопросы по PowerShell-автоматизации

С чего начать писать админские скрипты?
Начните с трёх задач, которые делаете руками каждый день: отчёт по отключённым учёткам, проверка свободного места на серверах, список последних входов. На каждой задаче тратится 15 минут — скрипт выполнит их за 5 секунд.
Как запускать скрипты по расписанию?
Используйте Task Scheduler с действием powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\daily.ps1. Обязательно от сервисной учётки с нужными правами, не от администратора.
Где хранить пароли в скриптах?
Никогда не в открытом виде. Используйте SecretManagement с vault CredMan или Azure Key Vault, либо Export-CliXml с DPAPI-шифрованием под конкретным пользователем. Я никогда не кладу пароли в текстовый файл скрипта.
Как отправить отчёт на почту?
Используйте Send-MailMessage (старый, но работает) или Microsoft.Graph для Microsoft 365. Параметры SMTP-сервера, порта, учётных данных и темы — обязательные. HTML-отчёт через ConvertTo-Html с кастомным CSS.
Где искать готовые модули?
PowerShell Gallery (Install-Module), GitHub (ImportExcel, PSWindowsUpdate, dbatools, PSFramework). Проверяйте подпись автора и количество загрузок — модули от PoshCode или Microsoft — безопасны.

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

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

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

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