Перейти к содержанию
Обсудить задачу →
Статьи и инструкции

Active Directory и PowerShell: 10 задач администратора с проверкой и возвратом

Практические команды PowerShell для AD: пароли, блокировки, группы, неактивные компьютеры, отчёты, проверка результата и безопасный возврат.
Active Directory и PowerShell: 10 задач администратора с проверкой и возвратом — техническая иллюстрация

PowerShell позволяет управлять AD воспроизводимо: сначала выбрать объект и зафиксировать состояние, затем выполнить ограниченное изменение и проверить результат на том же контроллере. Ниже — десять рабочих задач для домена Windows Server, а не команды для массового удаления. Примеры используют учебный домен corp.example, контроллер dc01.corp.example и OU Lab. Замените их своими значениями. Рабочая среда — Windows PowerShell 5.1 с RSAT, отдельная учётная запись с делегированными правами. Локальный запуск от администратора нужен для установки компонентов, но сам по себе не даёт полномочий в AD.

Перед началом установите RSAT на поддерживаемой редакции Windows и откройте отдельную административную сессию. Команду установки выполняйте только там, где компонент действительно отсутствует:

Get-WindowsCapability -Online -Name 'Rsat.ActiveDirectory.DS-LDS.Tools*'
Add-WindowsCapability -Online -Name 'Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0'
Import-Module ActiveDirectory
$dc = 'dc01.corp.example'
$ou = 'OU=Lab,DC=corp,DC=example'
Get-ADRootDSE -Server $dc | Select-Object defaultNamingContext
New-Item -ItemType Directory -Path C:\Admin\Evidence -Force

Проверьте, что defaultNamingContext соответствует нужному домену. Если модуль не найден — исправьте установку RSAT; если сервер недоступен — проверьте корпоративный DNS и доступ к AD Web Services. Не подменяйте выбранный контроллер случайным сервером: чтение и последующая запись должны иметь понятный источник. Документация модуля ActiveDirectory.

Процедура управления AD: область поиска, идентичность, снимок, изменение и контроль
Порядок проверки и настройки. Команды, ограничения и диагностика приведены в статье.

1. Сбросить пароль пользователя и назначить смену при входе

Сброс пароля — административная операция, которая отличается от смены пароля самим пользователем. До выполнения подтвердите личность заявителя через утверждённый канал, проверьте samAccountName, SID и OU. Совпадение отображаемого имени недостаточно: в разных подразделениях могут работать однофамильцы. Пароль вводится интерактивно, не попадает в текст скрипта или журнал команд.

$u = Get-ADUser -Identity 'lab.ivanov' -Server $dc -Properties Enabled,PasswordLastSet
$u | Select-Object SamAccountName,SID,DistinguishedName,Enabled,PasswordLastSet
$newPassword = Read-Host 'Временный пароль' -AsSecureString
Set-ADAccountPassword -Identity $u.ObjectGUID -Server $dc -Reset -NewPassword $newPassword -WhatIf
Set-ADAccountPassword -Identity $u.ObjectGUID -Server $dc -Reset -NewPassword $newPassword
Set-ADUser -Identity $u.ObjectGUID -Server $dc -ChangePasswordAtLogon $true
Get-ADUser -Identity $u.ObjectGUID -Server $dc -Properties pwdLastSet,PasswordLastSet |
    Select-Object SamAccountName,pwdLastSet,PasswordLastSet
Remove-Variable newPassword

WhatIf проверяет план вызова, но не доказывает, что пароль удовлетворяет политике. Ошибка сложности требует нового пароля; обход политики не нужен. pwdLastSet=0 означает требование смены при следующем входе. Для сервисных учётных записей этот сценарий не подходит: смена может остановить службу. Возвратить старый неизвестный пароль невозможно — при ошибке назначают новый согласованный пароль. Проверяйте также результирующую fine-grained policy через Get-ADUserResultantPasswordPolicy. Set-ADAccountPassword.

2. Отключить и включить учётную запись

Блокировка входа при увольнении должна быть привязана к заявке и времени. Сохраните GUID и исходное Enabled: возврат должен восстанавливать именно предыдущее состояние, а не всегда включать аккаунт. Отключение не завершает уже выданные сессии SaaS, VPN и приложения автоматически — эти системы проверяют отдельно.

$u = Get-ADUser 'lab.ivanov' -Server $dc -Properties Enabled
$before = $u | Select-Object ObjectGUID,SamAccountName,Enabled,DistinguishedName
$before | Export-Clixml C:\Admin\Evidence\account-before.xml
Disable-ADAccount -Identity $u.ObjectGUID -Server $dc -WhatIf
Disable-ADAccount -Identity $u.ObjectGUID -Server $dc
Get-ADUser $u.ObjectGUID -Server $dc | Select-Object SamAccountName,Enabled
# Возврат только после согласования
$old = Import-Clixml C:\Admin\Evidence\account-before.xml
if ($old.Enabled) { Enable-ADAccount -Identity $old.ObjectGUID -Server $dc }

Ожидаемый результат первого изменения — Enabled=False на выбранном DC. После репликации проверьте второй контроллер, если приложение обращается к нему. Access denied исправляют делегированием нужной операции в конкретной OU, а не выдачей Domain Admins оператору.

3. Разблокировать пользователя и найти причину повторной блокировки

Разблокировка без поиска источника помогает на несколько секунд, если старый пароль продолжает использовать телефон, задача или служба. Сначала найдите LockedOut в ограниченной OU; затем прочитайте событие 4740 на контроллерах, где фиксировалась блокировка. Поле CallerComputerName — подсказка, а не доказательство, что проблему создал человек за этим компьютером.

Search-ADAccount -LockedOut -UsersOnly -SearchBase $ou -Server $dc |
    Select-Object SamAccountName,DistinguishedName
Unlock-ADAccount -Identity 'lab.ivanov' -Server $dc -WhatIf
Unlock-ADAccount -Identity 'lab.ivanov' -Server $dc
Get-ADUser 'lab.ivanov' -Server $dc -Properties LockedOut | Select-Object LockedOut
Get-WinEvent -ComputerName $dc -FilterHashtable @{
    LogName='Security'; Id=4740; StartTime=(Get-Date).AddHours(-2)
} -ErrorAction Stop | ForEach-Object {
    $xml = [xml]$_.ToXml(); $fields = @{}
    foreach ($d in $xml.Event.EventData.Data) { $fields[$d.Name] = $d.'#text' }
    [pscustomobject]@{Time=$_.TimeCreated; User=$fields.TargetUserName; Caller=$fields.CallerComputerName}
}

Отсутствие события может означать, что вы смотрите другой DC, аудит не включён или журнал перезаписан. Не делайте вывод «атаки нет» из пустой выборки. Описание события 4740.

4. Найти пустые группы и проверить их назначение

Пустая группа может использоваться в файловой ACL, GPO, VPN или приложении. Удаление уничтожит её SID; новая группа с тем же названием не вернёт старый доступ. Следующий отчёт ищет отсутствие прямых member, но отдельно отмечает пользователей с primaryGroupID. Пустые результаты не разрешают удаление.

$groups = Get-ADGroup -Filter * -SearchBase $ou -Server $dc -Properties member,Description
$report = foreach ($g in $groups) {
    if (@($g.member | Where-Object { $_ }).Count -eq 0) {
        $rid = $g.SID.Value.Split('-')[-1]
        $primary = @(Get-ADUser -LDAPFilter "(primaryGroupID=$rid)" -Server $dc)
        [pscustomobject]@{Name=$g.Name;SID=$g.SID.Value;GUID=$g.ObjectGUID;PrimaryUsers=$primary.Count;Description=$g.Description}
    }
}
$report | Export-Csv C:\Admin\Evidence\empty-groups.csv -NoTypeInformation -Encoding UTF8

Область Get-ADUser здесь — домен, потому что primary group может быть вне OU группы. Перед выводом из эксплуатации ищите SID в ресурсах и назначайте владельца. Это самостоятельная проверка, описанная в статье о назначении группы AD.

5. Добавить пользователя в группу и отменить только собственное изменение

Определите группу по GUID, проверьте её категорию и scope. Для выдачи доступа требуется согласование владельца ресурса. Сохранённый список прямых участников позволяет отличить существовавшее членство от добавленного этой операцией.

$g = Get-ADGroup 'Lab-File-Readers' -Server $dc
$u = Get-ADUser 'lab.ivanov' -Server $dc
$members = @(Get-ADGroupMember $g.ObjectGUID -Server $dc)
$already = $members.ObjectGUID -contains $u.ObjectGUID
$members | Export-Clixml C:\Admin\Evidence\group-members-before.xml
if (-not $already) {
    Add-ADGroupMember -Identity $g.ObjectGUID -Members $u.ObjectGUID -Server $dc -WhatIf
    Add-ADGroupMember -Identity $g.ObjectGUID -Members $u.ObjectGUID -Server $dc
}
Get-ADGroupMember $g.ObjectGUID -Server $dc | Select-Object Name,ObjectGUID
# Согласованный возврат только нового членства
if (-not $already) {
    Remove-ADGroupMember -Identity $g.ObjectGUID -Members $u.ObjectGUID -Server $dc -Confirm
}

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

6. Получить прямой и вложенный состав группы

Прямой состав нужен для управления членством, рекурсивный — для понимания эффективного включения через вложенные группы. Get-ADGroupMember -Recursive разворачивает дерево, но не сохраняет полный путь вложенности и не заменяет проверку primary group, SIDHistory и внешних доверий.

$g = Get-ADGroup 'Lab-File-Readers' -Server $dc
Get-ADGroupMember $g.ObjectGUID -Server $dc |
    Select-Object Name,SamAccountName,ObjectClass,SID |
    Export-Csv C:\Admin\Evidence\members-direct.csv -NoTypeInformation -Encoding UTF8
Get-ADGroupMember $g.ObjectGUID -Recursive -Server $dc |
    Select-Object Name,SamAccountName,ObjectClass,SID |
    Export-Csv C:\Admin\Evidence\members-recursive.csv -NoTypeInformation -Encoding UTF8

Не смешивайте количество прямых и конечных участников в отчёте. Для межлесовых объектов могут понадобиться доступность другого леса и разрешения на чтение; ошибка не равна отсутствию членства. CSV содержит персональные сведения, поэтому храните его в административной папке с ограниченной ACL.

7. Найти неактивные компьютеры без автоматического удаления

LastLogonDate основан на реплицируемом lastLogonTimestamp и не является точным последним входом. Ноутбук в длительной командировке, резервный сервер и выключенная VM могут быть законными объектами. Выборка — кандидаты для сверки с инвентаризацией, владельцами и журналами.

$candidates = Search-ADAccount -AccountInactive -ComputersOnly -TimeSpan 90.00:00:00 -SearchBase $ou -Server $dc
$candidates | ForEach-Object {
    Get-ADComputer $_.DistinguishedName -Server $dc -Properties LastLogonDate,OperatingSystem,Enabled
} | Select-Object Name,ObjectGUID,Enabled,LastLogonDate,OperatingSystem,DistinguishedName |
    Export-Csv C:\Admin\Evidence\inactive-computers.csv -NoTypeInformation -Encoding UTF8

Если нужна точная оценка последней доменной аутентификации, собирают нереплицируемый lastLogon со всех DC и выбирают максимальное значение, учитывая недоступные источники. Даже это не показывает все локальные входы. Search-ADAccount.

8. Отключить подтверждённо выведенный компьютер

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

$c = Get-ADComputer 'LAB-PC01' -Server $dc -Properties Enabled
$c | Select-Object ObjectGUID,Enabled,DistinguishedName |
    Export-Clixml C:\Admin\Evidence\computer-before.xml
Disable-ADAccount $c.ObjectGUID -Server $dc -WhatIf
Disable-ADAccount $c.ObjectGUID -Server $dc
Get-ADComputer $c.ObjectGUID -Server $dc | Select-Object Name,Enabled
# Возврат исходного Enabled после согласования
$oldComputer = Import-Clixml C:\Admin\Evidence\computer-before.xml
if ($oldComputer.Enabled) { Enable-ADAccount $oldComputer.ObjectGUID -Server $dc }

Отдельно оформляют карантинную OU и GPO, если это предусмотрено процедурой. Перемещение объекта меняет применяемые политики; его нельзя считать безвредной заменой отключения. После возврата проверьте secure channel на самом клиенте, DNS и время, не начинайте с повторного ввода в домен.

9. Найти компьютеры по ОС и сформировать инвентаризационный отчёт

OperatingSystem в AD — полезный ориентир, но не подтверждение установленного build, патчей и состояния поддержки. Атрибут может быть устаревшим. Отчёт следует сверять с системой управления устройствами.

Get-ADComputer -Filter 'OperatingSystem -like "Windows*"' -SearchBase $ou -Server $dc -Properties OperatingSystem,OperatingSystemVersion,LastLogonDate |
    Select-Object Name,OperatingSystem,OperatingSystemVersion,LastLogonDate,Enabled |
    Sort-Object OperatingSystem,Name |
    Export-Csv C:\Admin\Evidence\windows-inventory.csv -NoTypeInformation -Encoding UTF8

На разрешённом доступном хосте можно отдельно получить Win32_OperatingSystem через CIM. Не трактуйте отсутствие ответа как факт отсутствия компьютера: firewall, WinRM, отключённое питание и права дают разные причины. Для планирования миграции фиксируйте также приложение, владельца, совместимость и срок замены.

10. Удалить аккаунт только после карантина и подготовленного восстановления

Удаление — финальная стадия вывода из эксплуатации, а не способ временно запретить вход. Export-Clixml сохраняет сведения для расследования, но не является резервной копией AD и не восстанавливает пароль или исходный SID. До удаления нужна проверенная процедура восстановления, например включённая AD Recycle Bin с подходящим сроком хранения; её включение — отдельное изменение леса.

Get-ADOptionalFeature -Filter 'Name -like "Recycle Bin Feature"' -Server $dc |
    Select-Object Name,EnabledScopes
$u = Get-ADUser 'lab.retired' -Server $dc -Properties memberOf,Enabled
$u | Export-Clixml C:\Admin\Evidence\retired-user.xml
if ($u.Enabled) { throw 'Сначала согласованный карантин и отключение' }
Remove-ADUser -Identity $u.ObjectGUID -Server $dc -WhatIf
# Выполнять только при подтверждённом выводе и готовом восстановлении
Remove-ADUser -Identity $u.ObjectGUID -Server $dc -Confirm

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

Нужно автоматизировать обслуживание Active Directory?

Скрипты эффективны вместе с контролем изменений, резервным копированием, журналами, моделью прав и проверяемым откатом.