Pending reboot на Windows-серверах: полный аудит через PowerShell
Я Семёнов Евгений Сергеевич, директор АйТи Фреш. За 15+ лет работы с Windows-парками встречал такое регулярно: приезжаешь к клиенту, а там 40 серверов и 23 из них уже две-три недели ждут перезагрузки после обновлений. Пользователи жалуются на тормоза, антивирус «не может обновиться», GPO не применяются — а причина проста: админ ставит патчи, но забывает их «довести» перезагрузкой. В этой статье — как за минуту проверить весь парк на pending reboot, какие ключи реестра смотреть и как правильно выстроить процесс, чтобы серверы перезагружались по плану, а не по настроению.
Что такое pending reboot
Когда Windows устанавливает обновление, драйвер или компонент, часть файлов заменить на лету невозможно — ими пользуется работающий процесс. Система помечает такие операции как «отложенные» и ставит флаг «pending reboot». После перезагрузки при старте Session Manager выполняет MoveFileEx и завершает установку.
Проблема: этот флаг не светится нигде в интерфейсе обычного сервера. Admin Center показывает у себя, SCCM клиент показывает, но на голом Windows Server Core это только в реестре. И если установили 5 апдейтов за месяц и не ребутнули — сервер накапливает технический долг. Каждый следующий патч может сломаться, потому что предыдущий не завершён.
Где Windows хранит флаги pending reboot
| Источник | Что проверять |
|---|---|
| Component Based Servicing | HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending |
| Component Based Servicing | HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress |
| Component Based Servicing | HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending |
| Windows Update | HKLM:\SOFTWARE\Microsoft\Windows\WindowsUpdate\Auto Update\RebootRequired |
| Windows Update | HKLM:\SOFTWARE\Microsoft\Windows\WindowsUpdate\Auto Update\PostRebootReporting |
| Session Manager | HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations |
| Computer Rename | Сравнение ActiveComputerName и ComputerName |
| SCCM Client | WMI: root\ccm\ClientSDK → CCM_ClientUtilities.DetermineIfRebootPending() |
Рабочий скрипт Test-PendingReboot
function Test-PendingReboot {
[CmdletBinding()]
param([string]$ComputerName = $env:COMPUTERNAME)
$sb = {
$flags = [ordered]@{
ComputerName = $env:COMPUTERNAME
CBSRebootPending = $false
WUARebootRequired = $false
PendingFileRename = $false
ComputerRenamePending = $false
CcmPending = $false
Summary = $false
}
$cbsKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending'
if (Test-Path $cbsKey) { $flags.CBSRebootPending = $true }
$wuaKey = 'HKLM:\SOFTWARE\Microsoft\Windows\WindowsUpdate\Auto Update\RebootRequired'
if (Test-Path $wuaKey) { $flags.WUARebootRequired = $true }
$sm = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
$pend = Get-ItemProperty -Path $sm -Name PendingFileRenameOperations -ErrorAction SilentlyContinue
if ($pend.PendingFileRenameOperations) { $flags.PendingFileRename = $true }
$active = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName').ComputerName
$current = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName').ComputerName
if ($active -ne $current) { $flags.ComputerRenamePending = $true }
try {
$ccm = Invoke-CimMethod -Namespace 'root/ccm/ClientSDK' `
-ClassName 'CCM_ClientUtilities' -MethodName 'DetermineIfRebootPending' `
-ErrorAction Stop
if ($ccm.RebootPending -or $ccm.IsHardRebootPending) { $flags.CcmPending = $true }
} catch { }
$flags.Summary = ($flags.CBSRebootPending -or $flags.WUARebootRequired -or
$flags.PendingFileRename -or $flags.ComputerRenamePending -or
$flags.CcmPending)
[pscustomobject]$flags
}
if ($ComputerName -eq $env:COMPUTERNAME) {
& $sb
} else {
Invoke-Command -ComputerName $ComputerName -ScriptBlock $sb -ErrorAction Stop
}
}
# Одиночная проверка
Test-PendingReboot -ComputerName srv-db01
Аудит всего парка за одну команду
$servers = Get-ADComputer -Filter { OperatingSystem -like '*Server*' -and Enabled -eq $true } |
Select-Object -ExpandProperty DNSHostName
$report = $servers | ForEach-Object -Parallel {
try { Test-PendingReboot -ComputerName $_ }
catch { [pscustomobject]@{ ComputerName = $_; Summary = 'Unreachable' } }
} -ThrottleLimit 15 -AsJob | Wait-Job | Receive-Job
$report | Where-Object Summary -eq $true | Sort-Object ComputerName |
Export-Excel -Path "C:\Scripts\Reports\pending-reboot-$(Get-Date -f yyyyMMdd).xlsx" `
-AutoSize -TableName Pending -ConditionalText @(
New-ConditionalText -Text 'True' -ConditionalTextColor 'White' -BackgroundColor '#d97000')
На 50 серверах скрипт отрабатывает за 40–80 секунд благодаря ForEach-Object -Parallel (PowerShell 7+). Для PS 5.1 используйте Start-ThreadJob или модуль PoshRSJob.
Мини-кейс: производство на 180 серверов
В октябре 2025 клиент — металлургический комбинат, инфраструктура из 180 Windows Server разных поколений. WSUS катит обновления автоматом, но перезагрузки не автоматизированы — делают руками по заявкам. В какой-то момент безопасники попросили «показать, где у нас уязвимости не запатчены». Запустили мой скрипт — из 180 машин 52 с pending reboot, 14 из них больше месяца. Четыре сервера — контроллеры домена, которые никто не перезагружал с мая.
Собрали Excel-отчёт, посчитали среднее время с момента первого pending reboot — 11 дней. Согласовали матрицу окон обслуживания (суб-сутки для DC, воскресенье 2:00–4:00 для файловых серверов, отдельные окна для 1С) и написали PowerShell-пайплайн, который по расписанию в окне обслуживания ребутит конкретный набор серверов, дожидается, проверяет сервисы и отправляет отчёт. Серверная плечо автоматизации — виртуалка на Dell с Xeon Platinum 8280 в дата-центре МТС, 40G Mellanox до кластера. За первый месяц работы пайплайна количество серверов с pending reboot упало с 52 до 3. Стоимость проекта 95 тыс. руб.
Автоматическая перезагрузка с проверками
Если решаете автоматизировать перезагрузки — ни в коем случае не просто Restart-Computer. Минимум: проверить сервисы до, поставить ping-мониторинг, проверить сервисы после, отправить отчёт, имейть механизм отката.
function Invoke-SafeReboot {
param([string]$Server, [string[]]$CriticalServices, [int]$TimeoutMinutes = 15)
Write-PSFMessage "Reboot $Server started"
$servicesBefore = Get-Service -ComputerName $Server -Name $CriticalServices |
Select-Object Name,Status
Restart-Computer -ComputerName $Server -Force -Wait -For PowerShell `
-Timeout ($TimeoutMinutes * 60) -Delay 5
Start-Sleep -Seconds 60 # подождать полной инициализации
$servicesAfter = Get-Service -ComputerName $Server -Name $CriticalServices |
Select-Object Name,Status
$broken = $servicesAfter | Where-Object Status -ne 'Running'
if ($broken) {
Write-PSFMessage -Level Warning "After reboot broken on $($Server): $($broken.Name -join ',')"
return $false
}
Write-PSFMessage "Reboot $Server OK, $(($servicesAfter | Where-Object Status -eq 'Running').Count) services up"
return $true
}
Интеграция с мониторингом
Аудит pending reboot должен быть не разовой командой, а постоянной метрикой. У меня на клиентах обычно это:
- Scheduled task на центральной виртуалке, раз в 6 часов обходит все серверы и пишет результат в PostgreSQL или CSV.
- Prometheus exporter парсит этот CSV и выдаёт метрику
pending_reboot_age_days{host="srv-01"}. - Grafana дашборд с top-10 самых «старых».
- Alertmanager правило: >3 дней pending reboot — warning, >14 — critical.
- Алерт в Telegram на техканал дежурной смены.
# Простой JSON для exporter
$now = Get-Date
$report | ForEach-Object {
[pscustomobject]@{
host = $_.ComputerName
pending = [int]$_.Summary
age_days = if ($_.Summary) { (New-TimeSpan -Start $_.FirstSeen -End $now).Days } else { 0 }
}
} | ConvertTo-Json | Out-File C:\metrics\pending_reboot.json -Encoding UTF8
Лучшие практики по перезагрузкам
- Согласовать матрицу окон обслуживания с заказчиком — для каждого типа сервера своё время.
- Никогда не перезагружать контроллеры домена одновременно. Всегда по одному с проверкой репликации.
- Перед ребутом снять дамп состояния критичных сервисов (
Get-Service, список открытых TCP-соединений, логи за час). - После ребута — runbook с проверками: сервисы подняты, порты слушаются, тестовый запрос к сервису прошёл.
- Логировать каждую перезагрузку с причиной: «KB5041571 pending reboot, applied on 2025-10-15 03:00».
- Недоступные сервера после ребута — отдельный лог и алерт немедленно.
- Для кластерных сервисов (SQL AlwaysOn, Exchange DAG, Hyper-V) использовать rolling-режим с failover, а не downtime.
Наведём порядок с перезагрузками на ваших серверах
Проведу аудит всего парка, покажу, сколько у вас серверов с pending reboot, помогу настроить окна обслуживания и автоматизировать процесс ребутов с проверками и откатом. 15+ лет опыта с Windows-парками до 800 рабочих мест, серверное плечо на Dell Xeon Platinum 8280 в дата-центре МТС на 40G Mellanox.
Телефон: +7 903 729-62-41
Telegram: @ITfresh_Boss
Семёнов Евгений Сергеевич, директор АйТи Фреш
FAQ — частые вопросы по pending reboot
- Почему Windows просит перезагрузку?
- Причины: установлены обновления CBS, WUA-апдейты ждут, PendingFileRenameOperations в реестре, смена имени компьютера, SCCM/Intune запросил reboot, драйверы обновлены. Windows помечает флаг, приложения должны его проверять.
- Какие ключи реестра проверять?
- Component Based Servicing/RebootPending и RebootInProgress, WindowsUpdate/Auto Update/RebootRequired, Session Manager/PendingFileRenameOperations, ComputerName/ActiveComputerName vs ComputerName. Полный список у автора PendingReboot модуля на GitHub.
- Как проверить через WMI?
- На серверах с установленным SCCM-клиентом — через namespace root\ccm\ClientSDK, метод DetermineIfRebootPending(). Без SCCM этот namespace недоступен, используйте реестр.
- Как устанавливать обновления и перезагружать автоматически?
- PSWindowsUpdate модуль: Install-WindowsUpdate -AcceptAll -AutoReboot. Но на продакшене никогда без окна обслуживания и нескольких слоёв согласований. Лучше WSUS + запланированная перезагрузка через scheduled task.
- Как исключить серверы из аудита?
- Через группу AD или список exclusion.txt. В скрипте Where-Object { $_.DNSHostName -notin $excluded }. Полезно для серверов, которые физически нельзя перезагрузить часто — 1С, АСУ ТП.