Потерянная группа. Выясняем назначение «странных» групп в AD

Так вот, мы видим группу, чешем затылок. В группе пользователи из разных подразделений. Никаких признаков на здравый смыл. Возможно, по названию группы мы смутно сможем определить (или догадаться), для чего она нужна. Это будет плюс тому, кто Вам все это оставил. Что же будем делать?

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

В чем смысл жизни групп? Как правило, это или доступ к ресурсам в расшаренных папках, или фильтр для применения групповых политик (не беру в расчет системные группы вроде Domain Admins etc.)
Значит задача для нас поставлена: нам надо проверить Access Control List (ACL) папок в расшаренных ресурсах и в групповых политиках.

Здравствуйте mr. PoSh

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

Групповые политики

Для работы с групповыми политиками нам поможет модуль grouppolicy. Из этого модуля мы используем два cmdlet`а:
1. get-gpo, который передает нам список всех групповых политик в домене
2. get-gppermissions, который позволяет нам просматривать ACL политик.
Затем, мы просто ищем совпадение между именем нашей группы и записью в ACL, и если таковые имеются, выводим сведения об этой политике:

$name=read-host "Введите полное имя учетной записи или группы"
Write-Host -Fore RED "Проверка в групповых политиках..."   
$gpos=get-gpo -all
Foreach ($gpo in $gpos)
    {
    $ACls=get-gppermissions -Name $gpo.DisplayName -all
    Foreach ($acl in $ACls)
        {
        if ($acl.Trustee.Name -match "$name") 
            {
            Write-Host -Fore GREEN "Найдена политика!"; $gpo
            If ($acl.Permission -eq "GpoApply") 
                {if ($acl.Denied) {Write-Host -Fore RED "Применение политики запрещено"}}
            }
        }
    }

Так же хочу отметить свойства Permission и Denied в ACL.
1. Permission — в нем записаны разрешения для объекта, например применение политики (GpoApply), чтение политики (GpoRead), изменение политики (GpoEdit) или вообще все сразу (GpoEditDeleteModifySecurity).
2. Denied показывает нам разрешено или запрещено то, что отображается в Permission.
Если посмотреть на кусок скрипта, то можно увидеть, что если в ACL группы, будет запрещено (Denied -eq $true) применение политики (Permission -eq «GpoApply»), то выведется уведомление об этом. В принципе можно было расписать уведомления для всех случаев, но меня интересует только запрет на распространение политики.
P.S. Переменную $name, в которой находится имя нашей группы, мы будем использовать и в следующих кусках кода.

Общие папки

Теперь займемся общими папками. Есть два варианта:
1. Когда разрешение дано непосредственно на расшаренный ресурс.
2. Когда разрешение дано на папку, спрятанную в недрах расшаренного ресурса.
Пойдем опять по порядку.

Ищем на поверхности

Самый простой и понятный способ, это давать разрешения на расшаренные папки. Так лучше и тем, что все разрешения у Вас в 1 месте, и не надо путать Ваших наследников, когда они докопаются до 4 слоя папок и найдут одну папку с фотографиями вашего дня рождения, куда был разрешен вход только вашей знакомой из Бухгалтерии. Потеряет она ярлычок, угадаете что за папка ей была нужна? Но к ней мы вернемся позже.
А сейчас нам необходимо проверить ACL на расшаренных папках на нашем файл-сервере (здесь он называется FileServer…(да, я оригинален)). Для этого мы используем всеми любимый WMI. Замечу, что я сразу отбрасываю в сторону папки, которые не отображаются при простом входе на наш сервер. Зачем? Обычные пользователи туда не залезут, ну а необычных, можно и спросить (при необходимости, можно убрать):

Write-Host -Fore RED "Проверка в папках \\FileServer"
$dirs=get-wmiobject win32_Share -computername FileServer | where-object {$_.Name -notmatch "\$"}
Foreach ($dir in $dirs)
    {
    Trap [System.UnauthorizedAccessException] 
    {"Был запрещен доступ к папке $share"; continue;}
    $out=$null
    $share=$dir.Path
    if ($share -match "^D:") {$share = $share.ToUpper().Replace('D:','\\FileServer\d$')}
    elseif ($share -match "^C:") {$share = $share.ToUpper().Replace('C:','\\FileServer\c$')}
    $out=($share | get-acl).Access | where-object {$_.IdentityReference -match "$name"}
    if ($out -ne $null) 
        {Write-Host -Fore green "Найдена папка!" $share}
    }

Также мы перехватываем ошибку, которая говорит нам, что доступ к определенным папкам закрыт, и вместо красных пугающих ошибок нам будет выводиться простое сообщение.
Две строчки, в которых мы заменяем ‘D:’ на ‘\\FileServer\d$’ (и аналогичное с диском ‘C’) необходимы, т.к. если этого не сделать, cmdlet get-acl будет пытаться искать эти папки на нашем компьютере и, скорее всего, не найдет. А искать по пути \\FileServer\Folder он (cmdlet get-acl) не может. В нашем примере только 2 диска, но добавить еще — не проблема.

Спускаемся в глубины

Возвращаемся к знакомой из бухгалтерии. Теперь копаемся в подпапках.
Я думаю многие скажут, зачем что то придумывать, когда можно использовать get-childitem -recurse. Если у Вас на сервере не очень много папок — да, можно использовать recurse. Но если у вас около 7 ТБ файлсервера, то проблемы, в принципе, тоже нет, надо всего лишь подождать пару часиков, и все сработает. И молите бога, что бы у вас не было ошибки на середине поиска.
Значит -recurse нам не поможет, что тогда? Тогда нам надо смастерить цикл, который по нашей прихоти будет углубляться в недра папок на столько, на сколько мы захотим (звучит как то пошло). Предположим, что у нас есть папка с подпапками для отделов (прошу простить за тавтологию). Эти папки не расшарены. В некоторых этих папках находятся нужные нам папки, с заветными разрешениями.

Write-Host -Fore RED "Проверка в папках \\FileServer\WorkFolders..."
$AllPath=@{}
$sub=4
$path=dir \\FileServer\c$\WorkFolders | where-object {$_.PSIscontainer}
$AllPath=$path
$cnt=0
For ($o=1; $o -lt $Sub; $o++)
{
    $PPath=$AllPath
    For ($i=$Cnt; $i -lt $PPath.Count; $i++)
        {
        $a = dir $PPath[$i].FullName | where-object {$_.PSIscontainer}
        if ($a -ne $null) {$AllPath = $AllPath + $a}
        }
    $cnt=$PPath.Count
}
Foreach ($WF in $AllPath)
    {
    Trap [System.UnauthorizedAccessException] 
    {"Был запрещен доступ к папке" + $WF.FullName; continue;}
    $out=$null
    $out=(get-acl $WF.FullName).Access | where-object {$_.IdentityReference -match "$name"}
    if ($out -ne $null) 
        {Write-Host -Fore GREEN "Найдена папка!"; $WF.FullName}
    }

Можно заметить, что нам нужны только папки, по этому мы фильтруем вывод с помощью свойства PSIscontainer.
Переменная $sub задает глубину поиска. В переменной $AllPath хранятся пути ко всем папкам, которые мы нашли. Ну а дальше, уже знакомые нам телодвижения, проверяют ACL найденных папок на наличие нашей группы в них.

В итоге

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

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *