Один журнал событий редко рассказывает историю целиком. Вход пользователя записан в журнале безопасности, упавшая следом служба - в системном, ошибка приложения, которое не дождалось этой службы, - в журнале приложений. Каждый журнал видит лишь свой кусок, и по отдельности эти куски почти бессмысленны. Целое рождается только когда записи из разных журналов выстраиваются рядом по времени и складываются в связную последовательность. Этот приём и называют корреляцией событий.

При анализе логов один журнал может не показывать ничего необычного, но группа связанных журналов раскрывает реальную картину. В этом и заключается ценность корреляции: она устанавливает временные, логические и причинно-следственные связи между событиями из разных источников, формируя цельное представление о происходящем. Сбой, который в одном журнале выглядит случайной ошибкой, в сопоставлении с соседними журналами оказывается закономерным звеном цепочки. Задача администратора - научиться сводить эти источники вместе и читать их как единый рассказ.

Почему события одного инцидента расползаются по разным журналам

Windows устроена так, что разные подсистемы пишут в разные каналы. Служба журнала событий поддерживает несколько основных каналов: система, приложение, установка и безопасность, и каждому соответствует свой журнал. Система фиксирует работу драйверов и служб, приложение - сообщения программ, безопасность - входы и изменения прав. Помимо этой четвёрки существуют десятки специализированных журналов в разделе приложений и служб, где свой канал ведёт чуть ли не каждый компонент.

Такое разделение логично с точки зрения устройства системы, но неудобно для анализа. Одно реальное событие из жизни компьютера почти всегда задевает сразу несколько подсистем и потому оставляет следы в нескольких журналах одновременно. Пользователь подключился по удалённому рабочему столу - запись ушла в журнал безопасности. Его сеанс запустил приложение, которое обратилось к недоступной службе - ошибка легла в журнал приложений, а отказ службы - в системный. Три журнала, один инцидент.

Дополнительную сложность создаёт то, что у журналов нет единой схемы. Анализ журналов Windows осложнён тем, что у разных журналов нет общей XML-схемы, поэтому специализированные инструменты опираются на шаблоны и сопоставление полей. Это значит, что свести журналы механически, просто склеив их, недостаточно. Нужен общий знаменатель, по которому записи из разных источников можно выстроить в ряд. Чаще всего таким знаменателем служит время.

Время как главная ось корреляции событий

Самый универсальный способ связать события из разных журналов - выстроить их по времени. У каждой записи есть точная отметка момента её создания, и если собрать события из нескольких журналов в общий список и отсортировать по этой отметке, получится единая хронологическая лента. По ней сразу видно, что за чем следовало и с каким интервалом.

В PowerShell это делается естественно. Командлет Get-WinEvent умеет читать любой журнал, его результаты легко объединить в один массив, а сортировка по полю времени создания выстраивает всё в нужном порядке. Пример ниже сводит ошибки журнала безопасности и системного журнала в общую ленту.

$security = Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4625}
$system   = Get-WinEvent -FilterHashtable @{LogName='System'; Level=2}
$security + $system | Sort-Object TimeCreated

После сортировки события из двух журналов идут вперемежку, строго по времени, и причинно-следственная связь становится видна. Если сразу за неудачным входом в системном журнале появляется отказ службы, два этих факта, разнесённые по разным журналам, наконец оказываются рядом и складываются в осмысленную сцену.

Чтобы лента читалась удобнее, к каждому событию полезно приписать, из какого журнала оно пришло, и оставить только ключевые поля. Тогда вместо громоздких объектов получается аккуратная таблица, по которой глаз скользит без усилий.

$security + $system |
    Sort-Object TimeCreated |
    Select-Object TimeCreated, LogName, Id, LevelDisplayName, Message |
    Format-Table -AutoSize

Сужение окна времени вокруг известного инцидента

Корреляция почти всегда отталкивается от какой-то опорной точки - известного момента, когда что-то пошло не так. Пользователь сообщил, что система зависла около трёх часов дня, или мониторинг зафиксировал сбой в определённую минуту. Дальше задача сводится к тому, чтобы вытащить из всех журналов события вокруг этого момента и посмотреть, что происходило в системе в тот промежуток.

Для этого выборку ограничивают узким временным окном через параметры начала и конца периода. Пример ниже собирает все ошибки и предупреждения из двух журналов за десятиминутный отрезок вокруг предполагаемого сбоя.

$start = Get-Date '2026-06-07 14:55'
$end   = Get-Date '2026-06-07 15:05'

'System','Application' | ForEach-Object {
    Get-WinEvent -FilterHashtable @{LogName=$_; Level=1,2,3; StartTime=$start; EndTime=$end}
} | Sort-Object TimeCreated

Узкое окно отсекает основную массу посторонних записей и оставляет только то, что происходило непосредственно вокруг инцидента. В такой плотной выборке причинно-следственная цепочка часто видна с первого взгляда: вот предупреждение драйвера, через секунду ошибка службы, ещё через две - падение приложения. Три журнала, выстроенные по минуте, рассказывают то, чего ни один из них не сказал бы в одиночку.

Связывание событий по общим полям, а не только по времени

Время - надёжная ось, но не единственная. События одного инцидента нередко делят общие значения полей: имя учётной записи, адрес источника, имя компьютера, идентификатор процесса. Если за инцидентом стоит конкретный пользователь, его имя всплывёт в записях разных журналов, и по нему их можно связать точнее, чем по одному только времени.

Сложность в том, что нужные поля лежат не в системной части события, а в данных, и у разных событий называются по-разному. Чтобы добраться до них, событие разворачивают в его внутреннее представление и достают значения из секции данных. Пример ниже извлекает имя пользователя из события входа, попутно показывая, как обращаться к скрытым полям.

$event = Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624} -MaxEvents 1
$xml = [xml]$event.ToXml()
$xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }

Получив значение из одного журнала, по нему фильтруют другие. Если в журнале безопасности нашёлся подозрительный пользователь, тем же именем прочёсывают системный журнал и журнал приложений, выискивая всё, что этот пользователь успел затронуть. Так корреляция переходит от грубого сопоставления по времени к точной привязке по сущности, и картина становится резче.

Полезно сразу нормализовать события из разных журналов к единому набору полей. Когда у всех записей в ленте одинаковые колонки времени, источника, пользователя и описания, сравнивать их между собой становится тривиально, даже если в исходных журналах эти данные хранились по-разному.

function Get-NormalizedEvent {
    param($Event)
    [PSCustomObject]@{
        Time    = $Event.TimeCreated
        Log     = $Event.LogName
        Id      = $Event.Id
        Level   = $Event.LevelDisplayName
        Message = $Event.Message -replace '\s+', ' '
    }
}

Удаление дубликатов и сбор событий с нескольких машин

При сведении множества файлов журналов возникает побочный эффект - повторяющиеся записи. Один и тот же сбой может оказаться зафиксирован дважды, особенно если журналы собирались с пересекающихся источников или экспортировались внахлёст. Удаление дубликатов при объединении файлов отсекает повторяющиеся записи и помогает выстроить точную временную шкалу, по которой удобно искать и фильтровать события. Без этой чистки лента распухает от повторов, а они сбивают с толку при подсчёте и анализе.

В реальной инфраструктуре инцидент часто затрагивает не одну машину, а несколько. Тогда корреляция расширяется по горизонтали: события собираются с парка компьютеров и сводятся в общую ленту, где у каждой записи помечено, с какой машины она пришла. Get-WinEvent умеет читать журналы удалённых компьютеров, и один скрипт способен обойти список серверов, забрать с каждого события нужного типа за период и слить всё в единый поток.

'srv01','srv02','srv03' | ForEach-Object {
    Get-WinEvent -ComputerName $_ -FilterHashtable @{LogName='Security'; ID=4625} |
        Select-Object @{N='Host';E={$_.MachineName}}, TimeCreated, Id, Message
} | Sort-Object TimeCreated

Когда одинаковая последовательность всплывает сразу на нескольких машинах в одно и то же время, это почти наверняка не локальная случайность, а общая причина - обновление, политика, сетевой сбой или скоординированная активность. Такую закономерность видно только при горизонтальной корреляции, когда журналы разных машин выстроены на одной временной оси.

Ручная корреляция через PowerShell прекрасно работает на разовом разборе одного инцидента или небольшого парка машин. Но когда счёт идёт на десятки серверов и миллионы событий в сутки, скриптов уже не хватает, и на сцену выходят специализированные системы сбора и анализа журналов. Они централизованно собирают, архивируют, ищут и сопоставляют записи из разрозненных систем, превращая разрозненные потоки в готовые отчёты. Такие системы строятся вокруг правил корреляции: администратор описывает шаблон подозрительной последовательности - например, множество неудачных входов, за которыми следует удачный, - и система сама ищет это сочетание в общем потоке, поднимая тревогу при совпадении. По сути это та же логика связывания по времени и общим полям, что и в ручных скриптах, только автоматизированная и работающая в реальном времени. Для эффективной корреляции эти системы используют события из множества источников: журналы операционных систем, сетевых устройств, средств защиты, серверов приложений и баз данных. Чем шире охват источников, тем полнее картина и тем раньше заметна аномалия.

Типичные цепочки событий и подводные камни корреляции по времени

Опыт корреляции во многом сводится к знанию характерных последовательностей. Некоторые цепочки повторяются из инцидента в инцидент, и научившись их узнавать, администратор экономит часы разбора. Классический пример - история подозрительного доступа. Сначала в журнале безопасности накапливается серия неудачных входов с кодом 4625, затем среди них проскакивает удачный вход с кодом 4624, а сразу за ним идут события создания процессов. Каждое событие по отдельности невинно, но выстроенные по времени они рисуют картину подобранного пароля и последующих действий.

Другая частая цепочка связывает сбой службы с отказом зависящего от неё приложения. В системном журнале появляется ошибка службы, а спустя секунды в журнале приложений - сообщение программы, которая не смогла к этой службе обратиться. Без корреляции администратор видит две независимые ошибки в двух журналах и тратит время, разбираясь с каждой порознь. С корреляцией он сразу понимает, что лечить нужно службу, а ошибка приложения - всего лишь следствие. Похожий сюжет разворачивается вокруг перезагрузок: событие завершения работы, за которым следует серия записей о старте служб, а потом ошибка той службы, что не поднялась, складывается в законченную историю проблемного старта.

Опора на время кажется надёжной, но у неё есть уязвимые места. Первая ловушка - расхождение часов между машинами. Когда события собираются с нескольких компьютеров, а их системные часы рассинхронизированы хотя бы на минуту, единая лента искажается: следствие может оказаться в ней раньше причины. Поэтому корреляция через парк машин имеет смысл лишь там, где время синхронизировано по единому источнику, и проверка синхронизации часов - обязательный первый шаг.

Вторая тонкость - разница между временем события и временем его записи. Большинство событий регистрируются мгновенно, но некоторые попадают в журнал с задержкой, и тогда их отметка времени слегка опаздывает относительно реального момента. На плотных цепочках, где события разделяют доли секунды, такая задержка способна перепутать порядок. Третий момент - часовые пояса и переход на летнее время: при анализе журналов с машин в разных поясах ленту легко прочитать неверно, если не привести все отметки к единому поясу. Осознавая эти ловушки, администратор доверяет временной ленте ровно настолько, насколько она того заслуживает, и подстраховывается общими полями и логической связью, которые не зависят от точности часов.

Что отличает корреляцию от простого просмотра журналов

Главный сдвиг в мышлении прост. Просмотр журнала - это чтение одного источника, корреляция - это чтение связей между источниками. Новичок открывает журнал безопасности, видит неудачный вход и закрывает вопрос. Опытный человек тут же спрашивает, что происходило в этот момент в системном журнале и в журнале приложений, и нередко обнаруживает, что безобидный на вид вход был началом цепочки, которая привела к сбою.

Корреляция превращает набор разрозненных фактов в историю с началом, серединой и концом. Время даёт оси, общие поля - привязку к действующим лицам, сведение машин - масштаб. А итогом становится восстановленная последовательность событий, по которой видно не только что сломалось, но и почему, и что этому предшествовало. Именно эта восстановленная цепочка и есть цель всей работы.

Журналы Windows честны, но молчаливы поодиночке. Они не выкрикивают вывод, они лишь фиксируют факты, каждый в своём углу. Связать эти факты в осмысленное целое - работа человека или настроенной им системы. И тот, кто умеет читать журналы не по отдельности, а в их взаимосвязи, видит в системе то, что для остальных так и остаётся набором не связанных между собой строчек.