PowerShell-скрипты, которые экономят моему отделу 8 часов в неделю
Я Семёнов Евгений Сергеевич, директор АйТи Фреш. За 15+ лет обслуживания корпоративных сетей мы выжали из PowerShell максимум, и сегодня у нас в отделе есть папка Scripts с 180 рабочими инструментами. Эта статья — выжимка самых ходовых скриптов, которые я пишу почти на каждом новом клиенте в первый же месяц. Отчёты по AD, инвентаризация железа, мониторинг дисков, проверка антивируса и служб — всё то, что без автоматизации отнимает часы ручной работы.
Базовая настройка рабочего окружения
Прежде чем писать полезные скрипты, подготовьте среду. VS Code с расширением PowerShell — стандарт де-факто. Установите PSReadLine последней версии, psake или Invoke-Build для тасков, Pester для тестов. Модули, без которых я не работаю:
| Модуль | Назначение | Команда установки |
|---|---|---|
| ActiveDirectory | Работа с пользователями, группами, компьютерами AD | RSAT: Install-WindowsFeature RSAT-AD-PowerShell |
| ImportExcel | Чтение/запись XLSX без установленного Excel | Install-Module ImportExcel -Scope CurrentUser |
| PSWindowsUpdate | Управление Windows Update удалённо | Install-Module PSWindowsUpdate |
| SecretManagement | Хранение паролей в защищённом хранилище | Install-Module Microsoft.PowerShell.SecretManagement |
| dbatools | Всё для SQL Server | Install-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 часов в неделю, что освободило помощника для реальной технической работы.
Автоматический запуск скриптов
Скрипт, который не запускается сам — не скрипт, а черновик. Варианты:
- Task Scheduler — стандартный способ для регулярных задач. Обязательно создаю сервисную учётку со «Log on as batch job» правами, а не пускаю от администратора.
- Планировщик Jenkins / GitLab CI — для более сложных пайплайнов с логированием и уведомлениями.
- WinRM триггеры — скрипт на центральном сервере опрашивает удалённые машины.
- Event-driven через WMI subscription — редко, но пригождается, когда надо реагировать на событие моментально.
# Пример регистрации задачи
$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-учёткам'
Логирование и мониторинг работы скриптов
Без логов у вас скрипты, которые «вроде работают». Минимум:
- Все скрипты пишут в
C:\Scripts\Logs\{имя}-YYYYMMDD.logчерезStart-Transcriptили модуль PSFramework. - Успешное завершение — событие в EventLog с source «PS-Scripts».
- Ошибки — отправка в Telegram или на почту дежурному инженеру.
- Ротация логов — старше 90 дней удалять по расписанию.
# Универсальная обёртка для любых скриптов
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 — безопасны.