Skip to content

HTML Телефонный справочник из Active Directory (Powershell)

PowerShell скрипт для создания динамического телефонного справочника из Active Directory
Схема работы простая - берет из AD нужные поля и генерит html-файл в указанном месте. 

Для удобства, городской-внутренний-мобильный хранятся в AD в полях Домашний-Пейджер-Мобильный (в стандартной оснастке они хранятся в одной вкладке). 

Скрипт требует PowerShell v1 и дополнение ActiveRoles ADManagement от компании Quest (бесплатное).
Можно запускать с нужным интервалом встроенным в windows шедулером. Естественно, нужно проверить, что у задачи на выполнения есть нужные права: читать из AD и писать в выходной файл.

HTML Телефонный справочник из Active Directory (Powershell)

Комментарии

Alexey

Если кому-то интерестно, то вот еще неплохой справочник: _ttp://www.pitin.su/news-64-0-0.htm Возможности: - отображение информации о сотрудниках (адреса электронной почты, телефоны, должности и др.) в виде таблицы; - сортировка по столбцам таблицы сотрудников; - поиск информации о сотрудниках по подстроке; - адаптированный для просмотра по отделам экспорт справочника в формат PDF; - адаптированный для просмотра по фамилиям экспорт справочника в формат PDF; - отображение подробной информации о сотруднике в новом окне; - отражение информации об иерархии сотрудников (список подчиненных, непосредственный начальник); - отображение предстоящих дней рождений сотрудников за n-дней; - отображение фото сотрудников.

vitas

клёво. потестю обязательно! тока один вопрос - зачем хранить даты рождения в MySQL, когда их можно хранить в AD? 

Гость

По умолчанию в AD нет поля для хранения даты рождения

vitas

по умолчанию нет, вы правы.
но, если стрёмно расширять схему, то можно использовать неиспользуемое в организации поле ("описание" или "заметки", f.e.). хотя бы на период тестирования? мне кажется, было бы удобнее. хотя, дело вкуса конечно ;)

Гость

Вот неплохой справочник _ttp://dmtsoft.ru/bn/702/as/oneaticleshablon - кстате можно изменять свои данные, например телефоны. Вот только ДР нет (

Гость

А дополнение ActiveRoles ADManagement от компании Quest необходимо устанавливать на сервер с ролью AD?

vitas

нет, на клиентскую машину, где запускается скрипт.

Владимир

Выбивает следующую ошибку. В чем может быть проблема?
Add-PSSnapin : Не удается добавить оснастку Quest.ActiveRoles.ADManagement Windows PowerShell,
а. Проверьте правильность имени оснастки и повторите попытку.
C:\Users\v.arnaut\Desktop\tel.ps1:3 знак:13
+ Add-PSSnapin <<<< Quest.ActiveRoles.ADManagement -passthru
+ CategoryInfo : InvalidArgument: (Quest.ActiveRoles.ADManagement:String) [Add-PSS
tion
+ FullyQualifiedErrorId : AddPSSnapInRead,Microsoft.PowerShell.Commands.AddPSSnapinCommand

vitas

Quest Active Roles не установлен на систему, где выполняется скрипт, я так понимаю.
надо установить (ссылка в статье есть).
сейчас он называется полностью "Quest ActiveRoles Management Shell for Active Directiry". соответственно, ставить надо 32bit/64bit в соответствии с тем, какая ОС утсановлена на системе, где выполняется скрипт.

Владимир

Дело в том, что как раз компонент установлен. Есть еще идеи?

vitas

текст ошибки который прислал - обрезан по-ходу, по-этому точно сказать трудно )
если текст:  
"Add-PSSnapin : Не удается добавить оснастку Quest.ActiveRoles.ADManagement Windows PowerShell, так как она уже добавлена. Проверьте правильность имени оснастки и повторите попытку."

то это нормально - при попытке вторично добавить одну и ту же оснастку оно ругается (но всё естественно работает), а заниматься её выгрузкой лень ;-)

пропиши пути к файлам и к нужному юниту в AD в скрипте и проверь. если компонент установлен, то должно всё работать.

Николай

C:\Users\sa\Desktop\tel.ps1:75 знак:14
+ Get-QADUser <<<< -SearchScope $sub -SearchRoot $oname -LDAPfilter '(!userAccountControl=66050)'|
+ CategoryInfo : NotSpecified: (:) [Get-QADUser], LdapFilterException
+ FullyQualifiedErrorId : Quest.ActiveRoles.ArsPowerShellSnapIn.BusinessLogic.LdapFilterException,Quest.ActiveRoles.ArsPowerShellSnapIn.Powershell.Cmdlets.GetUserCmdlet

Get-QADUser : Invalid filter format: 'userAccountControl=66050'

Вот такую ошибку получаю....

Николай

На каждой проходимой учетке

vitas

1) quest active roles вообще установлен? если открыть Powershell и в консоли набрать:

  • Add-PSSnapin Quest.ActiveRoles.ADManagement -passthru
  • get-qaduser
что напишет?

2) если в скрипте везде убрать "-LDAPfilter '(!userAccountControl=66050)'", то как отработает?

  • 49 строка: Get-QADUser -SearchRoot $oname|  
  • 75 строка: Get-QADUser -SearchScope $sub -SearchRoot $oname| 

Гость

В интернете нашёл ещё один интересный проект автономного телефонного справочника.
Автор использует всего 2 скрипта для автоматизации и сиквела у него нету...
Смотрим здесь:

Andre

vitas да так отрабатывае без ошибок но не чего не заносится в *.htm

vitas

сам файл .htm создается?/права на то, куда настроен вывод скрипта точно есть?в начале скрипта имя домена+OU прописаны правильно?в конце скрипта подразделения (OU) для добавления в справочник прописаны/прописаны правильно? полный путь совпадает? domain+otd должны складываться в полный путь до OU, откуда берутся юзеры.

Гость

Файл создает права присутствуют. В начале Имя домена/подразделение перепроверил все верно.

Вот только я не понял где в конце скрипта подразделения (OU) для добавления в справочник прописаны/прописаны правильно? полный путь совпадает?

Что у меня не правельно

Add-PSSnapin Quest.ActiveRoles.ADManagement -passthru

# папки и файлф куда кладем временные файлы и результат (index.htm)
# временный файл нужен для того, чтобы минимизировать время, когда пользователь будет видеть ошибку
$filemenu="c:\inetpub\wwwroot\menu.htm"
erase $filemenu
$fileto="c:\inetpub\wwwroot\teltmp.htm"
$filehtm="c:\inetpub\wwwroot\index.htm"

# имя домена и OU откуда будем начинать рекурсивный поиск пользователей
$domain= "test.local/test/test-users/"

# вначале телефонной книги будет общий список-ссылки по подразделениям.
# здесь указывается какое подразделение последнее в левом столбце (остальные будут во втором)
$perenos="Название заголовка, которое будет видеть пользователь2"

# заголовок страницы
$a = "Телефонный справочник ООО `"TEST`""

################## header html-страницы (втч стили и прочая херня) ######################

# стили и заголовок окна
$a = $a + ""
$a = $a + "BODY{background-color:#FFF;color:#000;font-family: tahoma; font-size: 8pt; }"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: #BFBFBF;border-collapse: collapse; width: 100%}"
$a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: #BFBFBF;background-color:#4E7DD1; color: #FFF}"
$a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: #BFBFBF;background-color:#FFF}"
$a = $a + "col#c1 { width: 10%;} col#c2{ width: 10%; }col#c3 {width: 10%;}col#c4 { width: 3%;}"
$a = $a + "col#c5 { width: 10%;} col#c6{ width: 11%; }col#c7 {width: 10%;}col#c8 { width: 25%;}"
$a = $a + ""

########### Функция вывода сверху списка линков на подразделения ########################
function links ($head)
{
$menu = $menu + ""+$head+""
$menu|Out-File -append $filemenu
}

############################## Вывод в HTML первого подразделения ###################################
function otdfirst
{
param ($oname, $head)
$oname=$domain+$oname
$head=""+$head+""

Select-Object sn, givenName, HomePhone, Pager, MobilePhone, physicalDeliveryOfficeName, mail, title|
sort sn|
ConvertTo-HTML -head $a -body $head|
Out-File $fileto
}

################# Функция вывода в хтмл. в нее передается назавание юнита и заголовок ################
function otd
{
param ($oname, $head, $sub)
$oname=$domain+$oname

# если это вложенный OU, то деелаем его заголовок маленький, иначе - большой
if ($sub -ne "SubTree")
{
$sub="OneLevel"
$header=""+$head+""
links ($head)
}
else
{
$header=""+$head+""
}

# LDAPFilter нужен для отсева заблокированных пользователей

# берем нужные поля из AD
Select-Object sn, givenName, HomePhone, Pager, MobilePhone, physicalDeliveryOfficeName, mail, title|
# сортируем по фамилии
sort sn|
# выводим в html
ConvertTo-HTML -body $header|
Out-File -append $fileto
$sub="OneLevel"
}

########################## Смена заголовков в таблица html-файла #######################################
# по-хорошему, надо добавить вырезание кучи хидеров html по документу и добавление одного нормального.
# иначе у нас фактически получается склейка нескольких html-файлов. но лениво, так как нормально работает и так =)
function proceedTab
{
$perenos=$perenos+""
$perenosNew=$perenos+ ""
$menu=Get-Content $filemenu
$menu= "" + "" +$menu + ""
$menu= $menu.replace($perenos,$perenosNew)

# Смена заголовков в таблицах подразделений на вменяемые русские, если меняли поля, которые брали из AD, нужно менять и их
(Get-Content $fileto) |
Foreach-Object {$_ -replace "sn", "Фамилия"} |
Foreach-Object {$_ -replace "givenname", "Имя"} |
Foreach-Object {$_ -replace "HomePhone", "Городской"} |
Foreach-Object {$_ -replace "Pager", "Внутренний"} |
Foreach-Object {$_ -replace "MobilePhone", "Мобильный"} |
Foreach-Object {$_ -replace "physicalDeliveryOfficeName", "Размещение"} |
Foreach-Object {$_ -replace "mail", "Почта"} |
Foreach-Object {$_ -replace "Company", "Компания"} |
Foreach-Object {$_ -replace "Department", "Подразделение"} |
Foreach-Object {$_ -replace "Title", "Должность"} |

# Добавляем сверху линки
Foreach-Object {$_ -replace "",$menu}|
Set-Content $fileto

# Выравниваем колонок по ширине. вот тут выползает хрень, что для меня осталось загадкой как по-человечески работать с переменными в несколько строк.
# именно из-за этого в html-е на выходе всё получается в одну строчку
$strText = Get-content $fileto
$Pattern = "\s\s\s\s\s"
$PatternTo = ""
$strReplace = [regex]::replace($strText, $pattern, $patternto)
$strReplace | out-file $fileto
}

##################### Сам скрипт. вызов в формате: "юнит отдела" "заголовок" ["SubTree"] ################
# "SubTree" нужно добавлять если есть подчиненный OU (и вы хотите, что бы он не был в списке
# подразделений сверху страницы и выделялся маленьким шрифтом)
######################################### Управления ####################################################

otdfirst "test/test-users" "test01"
otd "test/test-users" "test02"
otd "Управление2/Другое подразделение1" "Название заголовка, которое будет видеть пользователь3"
otd "Управления2/Другое подразделение2" "Название заголовка, которое будет видеть пользователь4"

################## Меняем заголовки таблиц на вменяемые русские, заменяем файл index.htm ################
proceedTab
links
move -force -path $fileto -destination $filehtm

Гость

Домен: test.local
OU : test

vitas

$domain+otd в итоге должны сложиться в полный путь.
если полные пути подрезделений "test.local/test/test-users/" и 
test.local/test/test-users2/", а в них двух лежат юзеры, то надо так:
$domain= "test.local/test/"
otdfirst "test-users" "test01"
otd "test-users2" "test02" 


Гость

Нужно принудительно поставить руководителя отдела в начало списка подразделения. Как это сделать?

vitas

я в оснастке AD в поле инфо ставил цифру (1,2,3 итд) и в скрипте добавлял сортировку по этому полю:

Get-QADobject -SearchRoot $oname -LDAPfilter '(&(objectcategory=person)(!userAccountControl=66050)(!userAccountControl=546)(!userAccountControl=514)(!userAccountControl=66082)(!info=TelOff))' -IncludedProperties sn, givenName, HomePhone, TelephoneNumber, Mobile, physicalDeliveryOfficeName, title,info|  sort info|

если вам нужно сортировать именно всех начальников в каждом отдельном подразделении, я бы по вхождению в поле "должность" слов "начальник", "директор" итд аналогично отсортировывал бы скриптом.