· 11 мин чтения

Аудит последнего входа в Active Directory: PowerShell, CSV и точные значения с разных контроллеров

Меня зовут Семёнов Евгений Сергеевич, я директор АйТи Фреш. За 15 лет работы с корпоративными доменами я перевидал десятки запросов «нам надо узнать, кто из сотрудников когда последний раз заходил в домен». Иногда это безопасность хочет почистить «спящие» учётки, иногда HR — сравнить со списком уволенных, иногда кадровый аудит ИБ-конторы. И почти всегда штатный администратор начинает с команды Get-ADUser -Filter * -Properties LastLogon и удивляется, почему данные «какие-то странные». Сегодня разбираю, как делать это правильно, какие подводные камни есть в атрибутах AD и как написать одну команду, которая выдаст вам корректный CSV для отчёта руководству.

Почему «простой» аудит даёт неверные данные

Active Directory хранит время последнего входа в нескольких атрибутах, и ни один из них не идеален. Разберёмся:

Если вам нужен «плюс-минус две недели» — хватает LastLogonDate. Если нужно точно «когда последний раз заходил» (например, для расследования инцидента) — придётся опрашивать все контроллеры. Я покажу оба способа.

Быстрый способ: LastLogonDate для всех пользователей

Самый простой случай — посмотреть, кто из активных пользователей не заходил в домен дольше N дней. Подходит для еженедельного аудита и согласования с HR. На любом контроллере домена или с RSAT-машины:

Import-Module ActiveDirectory

Get-ADUser -Filter {Enabled -eq $true} `
  -Properties LastLogonDate, DisplayName, Department, Title |
  Select-Object SamAccountName, DisplayName, Department, Title, LastLogonDate |
  Sort-Object LastLogonDate |
  Export-Csv "C:\Reports\AD-LastLogon-$(Get-Date -Format yyyyMMdd).csv" `
    -NoTypeInformation -Encoding UTF8

Через 30 секунд получаете CSV с отсортированным списком от самых старых дат входа к самым свежим. Идеально для отчёта в Excel — пустые LastLogonDate означают «никогда не входил» (свежесозданный аккаунт или сервисная учётка).

Точный способ: опрос всех контроллеров домена

Когда нужна точность до минуты (например, ИБ требует «во сколько именно последний раз заходил Иванов перед увольнением»), используем атрибут LastLogon. Он не реплицируется, поэтому надо опросить каждый контроллер и взять максимум:

$user = "ivanov"
$dcs = (Get-ADDomainController -Filter *).HostName
$logons = foreach ($dc in $dcs) {
  $u = Get-ADUser -Identity $user -Server $dc -Properties LastLogon
  [PSCustomObject]@{
    DC = $dc
    LastLogon = if ($u.LastLogon) { [DateTime]::FromFileTime($u.LastLogon) } else { $null }
  }
}
$logons | Sort-Object LastLogon -Descending | Format-Table -AutoSize
$max = ($logons | Where-Object LastLogon | Measure-Object LastLogon -Maximum).Maximum
Write-Host "Last logon (real): $max" -ForegroundColor Green

Для всех пользователей сразу — то же самое в цикле, но на больших доменах это занимает время. На 1000 пользователей × 4 контроллера это 4000 LDAP-запросов, занимает 5–15 минут в зависимости от сети.

Поиск неактивных учётных записей за один запрос

Если задача формулируется как «дайте всех, кто не заходил 90 дней», есть отдельный командлет, написанный именно под это:

Search-ADAccount -AccountInactive -TimeSpan 90.00:00:00 -UsersOnly |
  Where-Object {$_.Enabled -eq $true} |
  Select-Object SamAccountName, Name, LastLogonDate, DistinguishedName |
  Export-Csv "C:\Reports\Inactive-Users-90d.csv" -NoTypeInformation -Encoding UTF8

Командлет умный — он смотрит реплицированный LastLogonTimeStamp и работает на любом контроллере. Аналогичные команды есть для компьютеров (-ComputersOnly) и для заблокированных учёток (-LockedOut).

Чек-лист регулярного аудита неактивных учёток

В АйТи Фреш мы у клиентов настраиваем регулярный аудит по такой схеме:

  1. Раз в неделю — отчёт «не заходили 30 дней». Отправляем HR для сверки с увольнениями.
  2. Раз в две недели — отчёт «не заходили 60 дней». Согласовываем отключение учёток с непосредственным руководителем.
  3. Раз в месяц — отключение всех, кто не заходил 90 дней, с переносом в OU «Disabled». В описании учётки фиксируем дату отключения.
  4. Раз в полгода — удаление учёток, лежащих в Disabled больше 180 дней. Перед удалением — экспорт всех атрибутов и членств в группах в JSON-бэкап.

Скрипт для пункта 3, который мы запускаем по расписанию:

$inactiveDays = 90
$disabledOU = "OU=Disabled Users,DC=corp,DC=example,DC=ru"
$logFile = "C:\Logs\AD-Disable-$(Get-Date -Format yyyyMMdd).log"

Search-ADAccount -AccountInactive -TimeSpan "$inactiveDays.00:00:00" -UsersOnly |
  Where-Object {$_.Enabled -eq $true -and $_.DistinguishedName -notlike "*OU=Service*"} |
  ForEach-Object {
    try {
      Disable-ADAccount -Identity $_.SamAccountName
      Move-ADObject -Identity $_.DistinguishedName -TargetPath $disabledOU
      Set-ADUser -Identity $_.SamAccountName `
        -Description "Disabled $(Get-Date -Format 'yyyy-MM-dd') — inactive $inactiveDays+ days"
      Add-Content $logFile "OK $($_.SamAccountName) - $($_.LastLogonDate)"
    } catch {
      Add-Content $logFile "FAIL $($_.SamAccountName) - $_"
    }
  }
Send-MailMessage -From "ad-audit@itfresh.ru" -To "admin@itfresh.ru" `
  -Subject "AD inactive accounts disabled $(Get-Date -Format yyyy-MM-dd)" `
  -Body (Get-Content $logFile -Raw) -SmtpServer "mail.itfresh.ru"

Аудит компьютеров: забытые в домене ноутбуки

Помимо пользователей, в AD копится мусор из компьютерных учёток. Списанные ноутбуки, переустановленные ПК с новым именем, виртуалки из старых тестов. Они не безобидны — на них могут оставаться сертификаты, права в Wi-Fi, секреты Kerberos. Аудит — той же командой:

Search-ADAccount -AccountInactive -TimeSpan 60.00:00:00 -ComputersOnly |
  Where-Object {$_.Enabled -eq $true} |
  Select-Object Name, LastLogonDate, OperatingSystem, DistinguishedName |
  Sort-Object LastLogonDate |
  Export-Csv "C:\Reports\Inactive-Computers.csv" -NoTypeInformation -Encoding UTF8

На любом домене 100+ ПК этот отчёт покажет 5–15 «забытых» машин. Я обычно отключаю их сразу, а удаляю через 30 дней — на случай, если ПК просто долго лежал на полке и его принесли обратно.

Реальный кейс: 220 «спящих» учёток в торговой сети

В сентябре 2025 года к нам обратилась торговая сеть — 14 розничных точек, центральный офис, домен на 460 пользователей. Запрос от службы безопасности: «у нас за 4 года накопилось много старых учёток, надо почистить, потому что аудитор по 152-ФЗ нашёл 8 уволенных сотрудников с активным VPN-доступом».

Мы за полтора часа выгрузили полную картину:

После сверки с HR: 156 учёток — реальные уволенные сотрудники, не отключённые при увольнении. 28 — длительные декреты и больничные (их пометили в описании, отключать не стали). За три рабочих дня мы отключили все 156, перенесли в OU Disabled, отозвали сертификаты PKI, удалили из VPN-групп. Через месяц без жалоб удалили окончательно. Стоимость работ — 38 000 руб. С тех пор у клиента стоит наш скрипт, который раз в неделю присылает свежий отчёт на почту директора по безопасности.

Распространённые ошибки в скриптах аудита

За многие годы сборки таких отчётов я столкнулся с типовыми ошибками, которые искажают данные:

Bonus: однострочник для скоростного аудита

Если кто-то из руководства попросил «срочно дай список, кто не заходил больше месяца», и нужен быстрый ответ:

Get-ADUser -Filter {Enabled -eq $true} -Properties LastLogonDate |
  Where-Object {$_.LastLogonDate -lt (Get-Date).AddDays(-30)} |
  Select-Object SamAccountName, Name, LastLogonDate |
  Format-Table -AutoSize

За 5 секунд получаете табличку прямо в консоли. Дальше — Ctrl+A, Ctrl+C, вставить в письмо.

Наладим регулярный аудит AD под вашу инфраструктуру

Я лично выезжаю на бесплатный аудит AD в офисы Москвы и в радиусе 50 км от МКАД. За 2–3 часа смотрим состояние домена, делаем полный отчёт по неактивным учёткам, настраиваем автоматизацию ежемесячного аудита и интеграцию с вашим HR-процессом увольнения. Без обязательств.

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

FAQ — частые вопросы по аудиту последнего входа

Чем отличаются LastLogon и LastLogonTimeStamp?
LastLogon — точное время входа, но хранится только на том контроллере, к которому пользователь обращался, и не реплицируется. LastLogonTimeStamp реплицируется между контроллерами, но обновляется с задержкой 9–14 дней (по умолчанию).
Как получить точную дату последнего входа?
Опросить все контроллеры домена и взять максимальное значение LastLogon с каждого. Это даёт точность до минуты, но требует обращения ко всем DC, что на крупных доменах занимает время.
Как массово найти неактивных пользователей?
Используйте Search-ADAccount -AccountInactive -TimeSpan 90.00:00:00 -UsersOnly. Команда вернёт всех пользователей, не входивших в систему 90 дней. Дальше — экспорт в CSV, согласование с HR, отключение учёток.
Что делать с неактивными учётками?
Стандартная процедура: при отсутствии активности 90 дней — отключение через Disable-ADAccount, перенос в OU Disabled. После 180 дней без обращений HR — удаление через Remove-ADUser с предварительным резервным копированием атрибутов.
Как часто запускать аудит неактивных учёток?
Минимум раз в месяц, лучше — раз в две недели через запланированную задачу с отправкой отчёта на почту администратора. На динамичных доменах с частой текучкой — еженедельно.

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

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

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

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