Как выгрузить список пользователей из Active Directory. Использование Get-ADUser для получения разной информации о пользователях домена AD

Скрипты выгрузки всех пользователей из MS Active Directory (ITGC)

Иван Пискунов

Одной из стандартных процедур проведения аудита ITGC для каталога Active Directory является получение выгрузки всех пользователей домена. На основании полученных данных далее формируются процедуры тестирования, к примеру изучение списка администраторов или выявление пользователей с истекшим паролем. Наиболее эффективным для формирования такой выгрузки будет использование стандартного интерфейса PowerShell , примеры которого мы и рассмотрим в данной статье

1. Экспресс выгрузка скриптом на PowerShell

Ниже представлен скрипт PowerShell, как один из наиболее простых и быстрых способов получить список всех пользователей домена AD в формате CSV, который без проблем открывается тем же Excel"ем.

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher $objSearcher.SearchRoot = "LDAP://ou=Users,ou=Departmets,dc=test,dc=ru" $objSearcher.Filter = "(&(objectCategory=person)(!userAccountControl:1.2.840.113556.1.4.803:=2))" $users = $objSearcher.FindAll() # Количество учетных записей $users.Count $users | ForEach-Object { $user = $_.Properties New-Object PsObject -Property @{ Должность = $user.description Отдел = $user.department Логин = $user.userprincipalname Телефон = $user.telephonenumber Комната = $user.physicaldeliveryofficename ФИО = $user.cn } } | Export-Csv -NoClobber -Encoding utf8 -Path С:list_domen_users.csv

Для того что бы скрипт отработал на вашей системе, необходимо его чуть подкорректировать, а именно вписать необходимые параметры, т.е. как в данном примере это параметры Users в подразделении Departments в домене Test.ru. А так же указать путь к месту сохранения файла list_domen_users.csv

После выгрузки, если сразу открыть list_domen_users.csv , будет выглядеть в не читабельном виде, однако, станалртыми средствами мы легко его приведем в нужный нам формат. Открываем в Excel list_domen_users.csv , выделяем первый столбец, затем заходим во вкладку "Данные" и нажимаем "Текст по столбцам". Выбираем "с разделителями" и нажимаем "Далее". Готово!

!Необходимо заметить , что данный скрипт не отобразит более 1000 пользователей. Для небольшой компании вполне подойдет, а тем же у кого в домене огромное количество пользователей стоит прибегнуть к методам описанным ниже.

2. Продвинутый командлет PowerShell для получения выгрузки пользователей Active Directory

Инструмент Active Directory Module for Windows PowerShell (представлен в Windows Server 2008 R2 и выше), позволяет формировать командлеты которые выполняют различные манипуляции с объектами каталога AD. Для получения информации о пользователях и их свойствах предназначен командлет Get-ADUser.

Для начала запускаем окно Powershell с правами администратора и импортируем модуль Active Directory для дальнейших действия:
Import-Module activedirectory

Чтобы вывести список всех учетных записей домен а, выполним команду:

Get-ADUser -filter *

Чтобы вывести полную информации обо всех доступных атрибутах пользователя tuser, выполним команду

Get-ADUser -identity tuser -properties *


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

Get-ADUser -filter * -properties PasswordExpired, PasswordLastSet, PasswordNeverExpires | ft Name, PasswordExpired, PasswordLastSet, PasswordNeverExpires > C:tempusers.txt

Или сразу выгрузить в CSV , который в дальнейшем будет удобно экспортировать в Excel (дополнительно с помощью sort-object отсортируем таблицу по столбцу PasswordLastSet , а также добавим условие where – имя пользователя должно содержать строку «Dmitry»)

Get-ADUser -filter * -properties PasswordExpired, PasswordLastSet, PasswordNeverExpires | where {$_.name –like “*Dmitry*”} | sort-object PasswordLastSet | select-object Name, PasswordExpired, PasswordLastSet, PasswordNeverExpires | Export-csv -path c:tempuser-password-expires-2015.csv

В комментариях к предыдущей статье вспомнили про учет в Excel вместо 1С. Что ж, проверим, насколько вы знаете Excel. Сегодня я покажу, как получать данные из Active Directory и работать с ними без макросов и PowerShell - только штатными механизмами Office. Например, можно запросто получить аналитику по использованию операционных систем в организации, если у вас еще нет чего-либо вроде Microsoft SCOM. Ну, или просто размяться и отвлечься от скриптов.


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

Для работы с данными я буду использовать механизм Power Query . Для офиса 2010 и 2013 придется устанавливать плагин , в Microsoft Office 2016 этот модуль уже встроен. К сожалению, стандартной редакции нам не хватит, понадобится Professional.


Сам механизм предназначен для получения и обработки данных из самых разных источников ― от старого ODBC и текстовых файлов, до Exchange, Oracle и Facebook. Подробнее о механизме и встроенном скриптовом языке «M» уже писали на Хабре , я же разберу пару примеров использования Power Query для получения данных из Active Directory.

Разминка: посмотрим, когда наши пользователи логинились

Сам запрос к базе домена создается на вкладке «Данные ― Новый запрос ― Из других источников ― Из Active Directory».



Указываем источник данных.


Понадобится выбрать название домена, указать необходимые данные для подключения. Далее выберем тип объектов, в этом примере ― user . Справа в окне предпросмотра запрос уже выполняется, показывая предварительный вид данных.



Подготавливаем запрос, любуемся предпросмотром.


Предварительно запрос стоит подготовить, нажав кнопку «изменить» и выбрав нужные колонки. По сути эти колонки ― это классы Каждый из них содержит набор определенных атрибутов объекта Active Directory, кроме основной колонки displayName , которая сама является атрибутом. Я остановлюсь на классах user , person , top и securityPrincipal . Теперь необходимо выбрать нужные атрибуты из каждого класса с помощью «расширения» ― значок с двумя стрелочками у заголовка колонки:

  • класс user расширим, выбрав lastLogonTimestamp и userAccountControl ;
  • в person выберем telephoneNumber ;
  • в top whenCreated ;
  • и в securityPrincipal SamAccountName .


Расширяем запрос.


Теперь настроим фильтр: в частности, чтобы не получить заблокированные аккаунты, нужно чтобы атрибут userAccountControl имел значение 512 или 66048. Фильтр может быть другой в вашем окружении. Подробнее про атрибут можно прочитать в документации Microsoft .



Применяем фильтр .


Иногда Excel неверно определяет формат данных, особенно значения атрибута lastLogonTimestamp. Если вдруг постигла такая беда, на вкладке «Преобразовать» можно выставить верный формат.

Теперь столбец userAccountControl стоит удалить ― в отображении он не нужен совершенно. И нажимаем «Загрузить и закрыть».


Получилась табличка, которую осталось совсем немного довести до ума. Например, переименовать столбцы в что-то удобочитаемое. И настроить автоматическое обновление данных.


Автоматическое обновление при открытии таблицы или по таймауту настраивается во вкладке «Данные» в «Свойствах».



Настройка обновления данных.


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


Код запроса на языке «М» под спойлером.

let Источник = ActiveDirectory.Domains("domain.ru"), domain.ru = Источник{}[#"Object Categories"], user1 = domain.ru{}, #"Удаленные столбцы" = Table.RemoveColumns(user1,{"organizationalPerson", "shadowAccount", "posixAccount", "msExchOmaUser", "msExchBaseClass", "msExchIMRecipient", "msExchCertificateInformation", "msExchMultiMediaUser", "msExchMailStorage", "msExchCustomAttributes", "mailRecipient", "distinguishedName"}), #"Развернутый элемент securityPrincipal" = Table.ExpandRecordColumn(#"Удаленные столбцы", "securityPrincipal", {"sAMAccountName"}, {"sAMAccountName"}), #"Развернутый элемент top" = Table.ExpandRecordColumn(#"Развернутый элемент securityPrincipal", "top", {"whenCreated"}, {"whenCreated"}), #"Развернутый элемент person" = Table.ExpandRecordColumn(#"Развернутый элемент top", "person", {"telephoneNumber"}, {"telephoneNumber"}), #"Развернутый элемент user" = Table.ExpandRecordColumn(#"Развернутый элемент person", "user", {"lastLogonTimestamp", "userAccountControl"}, {"lastLogonTimestamp", "userAccountControl"}), #"Строки с применным фильтром" = Table.SelectRows(#"Развернутый элемент user", each ( = 512 or = 66048)), #"Измененный тип" = Table.TransformColumnTypes(#"Строки с примененным фильтром",{{"lastLogonTimestamp", type datetime}}), #"Удаленные столбцы1" = Table.RemoveColumns(#"Измененный тип",{"userAccountControl"}) in #"Удаленные столбцы1"

Создаем адресную книгу, или что делать, когда корпоративный портал с AD не дружит

Другой вариант использования Excel в связке с Active Directory ― это формирование адресной книги, исходя из данных AD. Понятно, что адресная книга получится актуальной, только если в домене порядок.


Создадим запрос по объекту user , развернем класс user в mail , а класс person в telephoneNumber . Удалим все столбцы, кроме distinguishedName ― структура домена повторяет структуру предприятия, поэтому названия Organizational Units соответствуют названиям подразделений. Аналогично в качестве основы названий подразделений можно использовать и группы безопасности.


Теперь из строки CN=Имя Пользователя, OU=Отдел Бухгалтерии, OU=Подразделения, DC=domain, DC=ru нужно извлечь непосредственно название отдела. Проще всего это сделать с использованием разделителей на вкладке «Преобразование».



Извлекаем текст.


В качестве разделителей я использую OU= и ,OU= . В принципе, достаточно и запятой, но я перестраховываюсь.



Вводим разделители.


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



Вид итоговой таблицы.

Быстрый отчет по составу рабочих станций, без внедрения агентов и прочей подготовки

Теперь попробуем создать полезную таблицу, получив данные по компьютерам. Сделаем отчет по используемым компанией операционным системам: для этого создадим запрос, но в навигаторе на этот раз выберем computer .



Делаем запрос по объекту computer.


Оставим классы-колонки computer и top и расширим их:

  • класс computer расширим, выбрав cn , operatingSystem , operatingSystemServicePack и operatingSystemVersion ;
  • в классе top выберем whenCreated .


Расширенный запрос.


При желании можно сделать отчет только по серверным операционным системам. Например, применить фильтр по атрибуту operatingSystem или operatingSystemVersion. Я не буду этого делать, но поправлю отображение времени создания ― мне интересен только год. Для этого на вкладке «Преобразование» выберем нужную нам колонку и в меню «Дата» выберем «Год».



Извлекаем год из времени ввода компьютера в домен.


Теперь останется удалить столбец displayname за ненадобностью и загрузить результат. Данные готовы. Теперь можно работать с ними, как с обычной таблицей. Для начала сделаем сводную таблицу на вкладке «Вставка» ― «Сводная таблица». Согласимся с выбором источника данных и настроим ее поля.



Настройки полей сводной таблицы.


Теперь остается настроить по вкусу дизайн и любоваться итогом:



Сводная таблица по компьютерам в AD.


При желании можно добавить сводный график, также на вкладке «Вставка». В «Категории» (или в «Ряды», по вкусу) добавим operatingSystem , в данные ― cn . На вкладке «Конструктор» можно выбрать тип диаграммы по душе, я предпочел круговую.



Круговая диаграмма.


Теперь наглядно видно, что, несмотря на идущее обновление, общее количество рабочих станций с Windows XP и серверов с Windows 2003 довольно велико. И есть к чему стремиться.


Код запроса под спойлером.

let Источник = ActiveDirectory.Domains("domain.ru"), domain.ru = Источник{}[#"Object Categories"], computer1 = domain.ru{}, #"Удаленные столбцы" = Table.RemoveColumns(computer1,{"user", "organizationalPerson", "person"}), #"Другие удаленные столбцы" = Table.SelectColumns(#"Удаленные столбцы",{"displayName", "computer", "top"}), #"Развернутый элемент computer" = Table.ExpandRecordColumn(#"Другие удаленные столбцы", "computer", {"cn", "operatingSystem", "operatingSystemServicePack", "operatingSystemVersion"}, {"cn", "operatingSystem", "operatingSystemServicePack", "operatingSystemVersion"}), #"Развернутый элемент top" = Table.ExpandRecordColumn(#"Развернутый элемент computer", "top", {"whenCreated"}, {"whenCreated"}), #"Извлеченный год" = Table.TransformColumns(#"Развернутый элемент top",{{"whenCreated", Date.Year}}), #"Удаленные столбцы1" = Table.RemoveColumns(#"Извлеченный год",{"displayName"}) in #"Удаленные столбцы1"

Добавить метки Используется для создания, изменения и удаления объектов каталога. Пользователь может также использовать команду ldifde для расширения схемы, экспорта сведений Active Directory о пользователе и группе в другие приложения или службы, а также для заполнения службы ADAM (Active Directory Application Mode) данными из других служб каталогов.

Синтаксис

ldifde [-i ] [-f имя_файла ] [-s имя_сервера ] [-c строка1 строка2 ] [-v ] [-j путь ] [-t номер_порта ] [-d DN_базы ] [-r фильтр_LDAP ] [-p область ] [-l список_атрибутов_LDAP ] [-o список_атрибутов_LDAP ] [-g ] [-m ] [-n ] [-k ] [-a ] [-b ] [-? ]

Параметры

-i Определяет режим импорта. Если параметр не определен, по умолчанию используется режим экспорта. -f имя_файла Указывает имя файла импорта или экспорта. -s имя_сервера Указывает компьютер, на котором должна выполняться операция импорта или экспорта. По умолчанию программа ldifde будет выполняться на компьютере, на котором ldifde установлена. -c строка1 строка2 Заменяет все вхождения строки1 содержимым строки2 . Обычно используется в случае, когда производится импорт данных из одного домена в другой, и при этом необходимо заменить различающееся имя домена, производящего экспорт (строка1 ), именем импортирующего домена (строка2 ). -v Включает режим подробного протоколирования. -j путь Задает местоположение файла журнала. По умолчанию используется текущий путь. -t номер_порта Указывает номер порта протокола LDAP (Lightweight Directory Access Protocol). По умолчанию используется порт LDAP 389. Портом глобального каталога является 3268. -d DN_базы Задает различающееся имя базы поиска для экспорта данных. -r фильтр LDAP Создает фильтр поиска LDAP для экспорта данных. Например, с помощью следующего фильтра выполняется экспорт всех пользователей с определенным отчеством: csvde -r (и(objectClass= Пользователь )(sn= Отчество )) -p область Задает область поиска. Параметрами области поиска являются Base , OneLevel и SubTree . -l список_атрибутов_LDAP Задает список атрибутов, возвращаемых в результатах запроса экспорта. Если данный параметр пропущен, возвращаются все атрибуты. -o список_атрибутов_LDAP Задает список атрибутов, опускаемых из результатов запроса экспорта. Обычно этот параметр используется при экспорте объектов из Active Directory с последующим импортом в другой LDAP-совместимый каталог. Если какие-либо атрибуты не поддерживаются другим каталогом, их можно исключить из набора результатов с помощью данного параметра. -g Исключает постраничные поиски. -m Опускает атрибуты, которые не могут быть записаны, такие как ObjectGUID и objectSID . -n Опускает экспорт двоичных значений. -k Игнорирует ошибки во время операции импорта и продолжает обработку. Ниже приводится полный список игнорируемых ошибок:

  • объект уже является членом группы;
  • нарушение класса объекта (означающее, что указанный класс объекта не существует), если импортируемый объект не имеет других атрибутов;
  • объект уже существует;
  • нарушение ограничения;
  • атрибут или значение уже существует;
  • такого объекта не существует.
-a различающееся_имя_пользователя пароль Задает выполнение команды с использованием указанных различающегося_имени_пользователя и пароля -b . -b имя_пользователя домен пароль Задает команду, выполняемую с использованием указанных имени_пользователя, домена и пароля . По умолчанию команда будет выполняться, используя учетные данные пользователя, который в текущий момент зарегистрирован в сети. Не может использоваться с параметром -a . -? Отображает меню команд.

Замечания

  • С параметром -c можно использовать константы #schemaNamingContext и #configurationNamingContext вместо различающихся имен раздела каталога схемы и раздела каталога конфигурации.
  • При создании файла импорта для команды ldifde , используйте значение changeType , чтобы определить тип изменений, содержащихся в файле импорта. Значения changeType приведены в таблице ниже.

Ниже приведен пример файла импорта LDAP формата LDIF, в котором используется значение add :
DN: CN= выбранный_пользователь ,DC= имя_домена
changetype: add
CN: выбранный_пользователь
description: описание_файла
objectClass: пользователь
objectClass: выбранный_пользователь

Примеры

Чтобы извлечь только различающееся имя, общее имя, имя, фамилию и номер телефона возвращенных объектов, введите:
-l различающееся_имя , CN, имя , SN, телефон
Чтобы исключить глобальный уникальный идентификатор (GUID) для объекта, введите:
-o когда_создан , когда_изменен , GUID_объекта

0

У меня есть следующий рабочий скрипт, который проверяет, является ли большой список пользователей в CSV-файле членом группы AD и записывает результаты в results.csv.

Не знаете, как преобразовать сценарий, чтобы я мог изменить $group = "InfraLite" на $group = DC .\List_Of_AD_Groups.CSV .

Таким образом, сценарий не просто возвращает совпадения для одной группы AD, но так что он возвращает совпадения для групп 80 AD, содержащихся в List_of_AD_groups.csv. Написание YES/NO для каждой группы AD в новом столбце CSV (или, если это невозможно, создание отдельного CSV-файла для каждой группы с результатами будет также.

Я мог бы сделать это вручную, изменив значение из $group и имя файла экспорта и повторного запуска скрипта в 80 раз, но должен быть быстрым был с PS, чтобы сделать это

например results.csv ?:

NAME AD_GROUP1 AD_GROUP2 AD_GROUP80 etc etc. user1 yes no yes user2 no no yes user3 no yes no echo "UserName`InfraLite" >> results.csv $users = GC .\user_list.csv $group = "InfraLite" $members = Get-ADGroupMember -Identity $group -Recursive | Select -ExpandProperty SAMAccountName foreach ($user in $users) { if ($members -contains $user) { echo "$user $group`tYes" >> results.csv } else { echo "$user`tNo" >> results.csv } }

  • 2 ответа
  • Сортировка:

    Активность

0

тривиальное решение вашей проблемы было бы обернуть ваш существующий код в другом цикле и создать выходной файл для каждой группы:

$groups = Get-Content "C:\groups.txt" foreach ($group in $groups) { $members = Get-ADGroupMember ... ... }

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

$template = @{} Get-Content "C:\groups.txt" | ForEach-Object { $template[$_] = $false } $groups = @{} Get-ADGroup -Filter * | ForEach-Object { $groups[$_.DistinguishedName] = $_.Name } Get-ADUser -Filter * -Properties MemberOf | ForEach-Object { $groupmap = $template.Clone() $_.MemberOf | ForEach-Object { $groups[$_] } | Where-Object { $groupmap.ContainsKey($_) } | ForEach-Object { $groupmap[$_] = $true } New-Object -Type PSObject -Property $groupmap } | Export-Csv "C:\user_group_mapping.csv" -NoType

0

я играл с этим на некоторое время, и я думаю, что я нашел способ, чтобы получить Вас именно то, что вы были после.

Я думаю, что Ansgar был на правильном пути, но я не мог заставить его делать то, что было после. Он упомянул, что на момент написания статьи он не имел доступа к среде AD.

Вот что я придумал:

$UserArray = Get-Content "C:\Temp\Users.txt" $GroupArray = Get-Content "C:\Temp\Groups.txt" $OutputFile = "C:\Temp\Something.csv" # Setting up a hashtable for later use $UserHash = New-Object -TypeName System.Collections.Hashtable # Outer loop to add users and membership to UserHash $UserArray | ForEach-Object{ $UserInfo = Get-ADUser $_ -Properties MemberOf # Strips the LPAP syntax to just the SAMAccountName of the group $Memberships = $UserInfo.MemberOf | ForEach-Object{ ($_.Split(",")).replace("CN=","") } #Adding the User=Membership pair to the Hash $UserHash.Add($_,$Memberships) } # Outer loop to create an object per user $Results = $UserArray | ForEach-Object{ # First create a simple object $User = New-Object -TypeName PSCustomObject -Property @{ Name = $_ } # Dynamically add members to the object, based on the $GroupArray $GroupArray | ForEach-Object { #Checking $UserHash to see if group shows up in user"s membership list $UserIsMember = $UserHash.($User.Name) -contains $_ #Adding property to object, and value $User | Add-Member -MemberType NoteProperty -Name $_ -Value $UserIsMember } #Returning the object to the variable Return $User } #Convert the objects to a CSV, then output them $Results | ConvertTo-CSV -NoTypeInformation | Out-File $OutputFile

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