Перемещаем информацию о пользователях в Active Directory и Sharepoint c помощью PowerShell

от автора

     Бывает так — что в крупной организации, подчиненной сложным корпоративным правилам — возникает несколько точек проникновения информации из реального мира в мир production! Например — мелкая торговая фирма вела список своих сотрудников в 1С — с помощью нанятого со стороны сотрудника отдела кадров — а потом — раз, и выросла в большую фирму — с разветвленной сетью филиалов и большой IT — инфрастуктурой! Нанято большое количество сотрудников — на скорую руку (с привлечением интеграторов, разумеется)  построена AD инфраструктура — заведены пользователи, настроены сайты, групповые политики работают, etc… и вдруг — оказывается, что информации в AD о пользователях — ноль! ну то есть имя — фамилия,  OU, членство в группах, пароль, logon-скрипт — и все! ни тебе имени, ни комнаты, ни телефона — где он и кто он — пустые поля. Что делать???

     Или вот взять мою ситуацию — пришел работать маленьким винтиком большой корпоративной системы! Она распределена по всей стране — и была не организована — но за время моей работы — подтянулась к реалиям современного мира, и вместо отдельно взятого домена в каждом филиале, не связанным с остальными — построила большое AD на всю страну! И поехали мои пользователи в новое прогрессивное будущее через ADMT, и их рабочие станции поехали, и они сами! И быстро организовались и OU, и групповые политики с логон — скриптами, действующими WMI — фильтрами и прочее — прочее! Да только вот старый их домен не хранил никаких знаний о них — ни о кабинете, где сидят, ни о том, как их зовут толком, ни об отделе, где трудятся! И так они поехали, простите, голыми в новый домен, что уже само по себе неприлично! А отсюда выросла задача первая:

1) Заполняем данные о пользователе в AD с помощью powershell


Надо сказать — что, несмотря на то, что филиал у нас был отдаленный  от центра как России, так и организации — но есть и у нас увлеченные люди! Ну, а куда без них! И поэтому в свое время — одним из хороших товарищей была написана утилита к местному кадровому 1С: Предприятие, — которая позволяла выгрузить все, что ведет отдел кадров по сотруднику — в обычную Excel-таблицу. Есть Excel — есть powershell — значит можно запихать данные в AD! Поехали:

Здесь я немного отступлю, и расскажу, что вообще надо для того, что бы с помощью powershell начать общаться с AD.

Есть первый путь для начала общения с AD из Powershell — это установка на рабочую станцию пакета Microsoft Remote Server Administration Tolls (RSAT). Кроме того, что бы все заработало — на вашем контроллере домена должны быть установлены web-службы active directory, что не всегда возможно. Например, в своем филиале я могу администрировать свою OU – но не могу, что — либо ставить на контроллер домена – прав не хватает.

Но есть выход и из этой ситуации. Хорошая фирма Quest Software разработала свое бесплатное решение для обращения к AD из PowerShell – Active Roles Management Shell for Active Directory (ссылка). Пакет так же ставиться на рабочую станцию c операционной системой не ниже Windows XP. На контроллер домена в данном случае ставить ничего не нужно – все работает из коробки.

Итак, вернемся к задаче получения информации из таблицы excel. Сама таблица выглядит следующим образом:

Все данные являются выдуманными – нам же не надо проблем с разглашением персональных данных.
При этом в нашем AD есть только данные по фамилии, имени и отчеству – следовательно, это и будет ключевым полем. Начинаем писать.
Сначала необходимо подгрузить библиотеку Active Roles Management Shell for Active Directory. В открытой консоле powershell это можно сделать следующей командой:
Add-pssnapin Quest.ActiveRoles.ADManagement

Тоже самое надо написать в файл скрипта, что бы не подключать модуль руками.
Дальше приведу весь код с комментариями:

# очищаем экран cls #Задаем путь к справочнику сотудников  $TelSPR="C:\info2AD\телефонный.xls"  #Имя листа (WorkSheet) рабочей книги Excel  $SheetName="Лист1"  #"Запускаем" Excel (создаем COM-объект Excel.Application)  $objExcel=New-Object -comobject Excel.Application  #выполняем открытие файла ("Рабочей книги") в Excel  $objWorkbook=$objExcel.Workbooks.Open($TelSPR)   #Номер колонки, содержащей ФИО $ColumnName=1 #Номер колонки, содержащей должность $ColumnTitle=2  #номера телефонов $ColumnHomePhone=3 $ColumnPhone=4 $ColumnMobPhone=5  #Комната $ColumnOffice=6  $ColumnMail=7 #Департамент $ColumnDep=8 # #Константа для использования с методом SpecialCells $xlCellTypeLastCell = 11 # #Получаем номер последней используемой строки на листе #$TotalsRow=$objWorkbook.Worksheets.Item($SheetName).UsedRange.SpecialCells($xlCellTypeLastCell).CurrentRegion.Row   #Выполняем перебор строк в открытом файле Excel for ($Row=1;$Row -le $TotalsRow; $Row++) {     #Сохраняем в переменных значения соответствующих ячеек     $UserName=$objWorkbook.ActiveSheet.Cells.Item($Row, $ColumnName).Value()     $Title=$objWorkbook.ActiveSheet.Cells.Item($Row, $ColumnTitle).Value()     $HomePhone=$objWorkbook.ActiveSheet.Cells.Item($Row, $ColumnHomePhone).Value()     $Phone=$objWorkbook.ActiveSheet.Cells.Item($Row, $ColumnPhone).Value()     $MobPhone=$objWorkbook.ActiveSheet.Cells.Item($Row, $ColumnMobPhone).Value()      $Office=$objWorkbook.ActiveSheet.Cells.Item($Row, $ColumnOffice).Value()     $Mail=$objWorkbook.ActiveSheet.Cells.Item($Row, $ColumnMail).Value()     $Department=$objWorkbook.ActiveSheet.Cells.Item($Row, $ColumnDep).Value()      #разбиваем ФИО, так как в AD это разные поля $arrfio =-split $UserName  $arrfio[2]=$arrfio[2].Substring(0,1)  # Добавляем префикс к номеру телефона if ($Phone -ne $null)     {   $Phone="(888) "+$Phone }  if ($MobPhone -ne $null)         { $MobPhone="(888) "+$MobPhone }           #Пишем данные в AD, если пользователь включен  (enabled), включаем обработку ошибок             try {                 Get-QADUser -DisplayName $UserName -enabled | Set-QADUser -FirstName $arrfio[1] -Initials $arrfio[2] -LastName $arrfio[0] -Department $Department -HomePhone $HomePhone -Phone $Phone -MobilePhone $MobPhone -Office $Office -Title $Title -Company "ООО Комета" -Mail $Mail             }             catch {                 $ReportString=("{0,-50} <-> {1,50}" -f $UserName, "Ошибка записи")             }    write-Host $reportString 	$reportString=" " } #Закрываем книгу Excel  $objExcel.Workbooks.Close()  #Выходим из Excel (вернее даем команду на выход из Excel) $objExcel.Quit() #обнуляем объект $objExcel = $null  #запускаем принудительную сборку мусора для освобождения памяти и окончательного завершения процесса [gc]::collect() [gc]::WaitForPendingFinalizers() 

Вот такой скрипт. Работает достаточно быстро. Скажем, список из 300 человек, обрабатывается не дольше минуты. Скрипт также можно повесить в запланированные задачи и попросить отдел кадров выгружать файл с данными сотрудников куда-нибудь в сетевую папку при изменении штатного расписания. Тогда в AD вы будете иметь соответствующую реалиям структуру.

2) Забираем данные из AD в список Sharepoint

После внедрения в нашей конторе Microsoft Sharepoint возникла необходимость использовать списки сотрудников внутри этого монстрообразного детища Microsoft. И опять нам на помощь приходит Powershell.
Для начала заберем данные из AD в текстовый файл формата csv – делается это в две строки:
Add-pssnapin Quest.ActiveRoles.ADManagement
$user=get-qaduser -SearchRoot «OU=Accounts,OU=comenta,DC=domen,DC=local»|Select-Object GivenName, DN, DisplayName, mail, LogonName, telephoneNumber, Office, Department, Title, HomePhone, MobilePhone, sid |Export-CSV -delimiter ";" -path «C:\PowershellScripts\ADUsers.csv» -Encoding UTF8

Можно было бы отгружать в csv и все данные по пользователям – но мы обратили внимание –что время работы скрипта тогда существенно увеличивается.
А уже следующим скриптом грузим данный файл в список Sharepoint. Приведу текст целиком, но под катом – я думаю, будет полезно:

Скрипт создания списков в Sharepoint

  ##################################################################################  param([string]$path, [string]$url,[string]$ou,[switch]$help)  [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")   #функция помощи  function GetHelp() {   $HelpText = @"  Описание:  Данный скрипт используется для актуализации данных списка пользователей. Предварительно данные из ActiveDirectory должны быть экспортированы в *.csv файл. Из csv файла в список SharePoint'а забираются следующие столбцы: * sn              - Фамилия * givenName       - Имя * DisplayName     - Полное имя (Ф.И.О.) * mail            - E-mail адрес * LogonName       - Логин * telephoneNumber - Телефонный номер ВТС * Office          - Кабинет * Department      - Отдел * Title           - Должность * HomePhone       - Домашний телефон (в нашем случае Городсокй телефон ) * MobilePhone     - Телефонный номер мобильный -------------------------------------------------------------------------------- Параметры:  -path		Путь расположения csv файла, откуда будут импортироваться данные -url		http путь расположения конечного списка, куда будут импортироваться данные -ou         Указать Organization unit в AD, откуда будут импортироваться пользователи,  например: OU=accaunts- загрузяться все пользователи. OU=cometa - загрузяться только пользователи филиала -------------------------------------------------------------------------------- Синтаксис:  Запуск скрипта из PowerShell: .\ImportADUsersToSPList.ps1 -path "Your path" -url "List URL" -ou "OU=cometa"  Вызов справки: .\ImportADUsersToSPList.ps1 -help  -------------------------------------------------------------------------------- Синтаксис:  Запуск скрипта из командной строки Windows: powershell .\ImportADUsersToSPList.ps1 -path "Your path" -url "List URL" -ou "OU=Magadan"  Вызов справки: powershell .\ImportADUsersToSPList.ps1 -help -------------------------------------------------------------------------------- "@ $HelpText  }  function nz($value) {	if ($value -eq $null) { 		$value="" 	}  return $value }  function UpdateList([string]$path,[string]$url,[string]$ou)  { #Загружаем необхоимые данные и вводим переменные: $site=New-Object Microsoft.SharePoint.SPSite($url) $web=$site.OpenWeb() $list=$web.GetList($url) $csv_file=Import-Csv -Delimiter ";" $path $listItems=$list.Items $spFiledType=[Microsoft.SharePoint.SPFieldType]::Text  #########################################################  #В цикле проверяем каждую строку csv файла и заносим данные в список: #пишем  лог: "Script started at:" | Out-File -encoding default ".\UpdateUsers.log" -Append Get-Date | Out-File -encoding default ".\UpdateUsers.log" -Append 	foreach ($line in $csv_file) { 		$update=$false         if (!($item=$list.Items | where {$_["Sid"] -eq $line.Sid})) {  			#убираем служебные учетные записи 			if (!(select-string -pattern "88" -inputobject $line.givenName) -and (!(select-string -pattern "Admin" -inputobject $line.givenName)) -and (!(select-string -pattern "Operator" -inputobject $line.givenName))-and ((select-string -pattern $ou -inputobject $line.DN))) 			{	Write-Output $line 				$item=$list.Items.Add() 				$item["Sid"]=$line.Sid                 $update=$true 			} else {continue} 		}         [array]$sids+=$line.Sid         		$t=$line.DisplayName -split " ",3         if ((nz($item["Фамилия"])) -ne (nz($t[0])))             {              $item["Фамилия"]=$t[0]              $update=$true              } 		if ((nz($item["Имя"])) -ne (nz($t[1])))             { $item["Имя"]=$t[1]             $update=$true             } 		 		if ((nz($item["Отчество"])) -ne (nz($t[2])))             { $item["Отчество"]=$t[2]             $update=$true             }             $tfioname=$t[1] -split "",3  		    $tfioMidName=$t[2] -split "",3 		    $fio=$t[0]+" "+$tfioname[1]+"."+$tfioMidName[1]+"." 	if ((nz($item["Ф.И.О."])) -ne (nz($fio)))             { $item["Ф.И.О."]=$fio             $update=$true             } 		$fio=$tfioname[1]+"."+$tfioMidName[1]+". "+$t[0] 	if ((nz($item["И.О.Ф."])) -ne (nz($fio)))             { $item["И.О.Ф."]=$fio             $update=$true             } 		if ((nz($item["E-mail"])) -ne (nz($line.mail)))             { $item["E-mail"]=$line.mail             $update=$true             } 		if ((nz($item["Логин"])) -ne (nz($line.LogonName)))             { $item["Логин"]=$line.LogonName              $update=$true             } 		if ((nz($item["ВТС"])) -ne (nz($line.telephoneNumber)))             { $item["ВТС"]=$line.telephoneNumber              $update=$true             } 		if ((nz($item["Кабинет"])) -ne (nz($line.Office)))         	{ $item["Кабинет"]=$line.Office              $update=$true             } 		if ((nz($item["Отдел"])) -ne (nz($line.Department)))             { $item["Отдел"]=$line.Department              $update=$true             } 		if ((nz($item["Должность"])) -ne (nz($line.Title)))             { $item["Должность"]=$line.Title              $update=$true             } 		if ((nz($item["ГТС"])) -ne (nz($line.HomePhone)))             { $item["ГТС"]=$line.HomePhone              $update=$true             } 		if ((nz($item["DECT"])) -ne (nz($line.MobilePhone)))             { $item["DECT"]=$line.MobilePhone              $update=$true             } 		if ($update -eq $true)            {          $item.Update()             } 	}     $listItems=$list.Items      for ($x=$listItems.Count-1; $x -ge 0; $x--)          {         if (($sids | where {$_ -eq $listItems[$x]["Sid"] }) -eq $null)             {             $notify="Удален пользователь: "+ $listItems[$x]["Фамилия"].ToString()             $notify | Out-File -encoding default ".\UpdateGUUsers.log" -Append             $listItems[$x].Recycle()             }         } "Script finished at:" | Out-File -encoding default ".\UpdateGUUsers.log" -Append         Get-Date | Out-File -encoding default ".\UpdateGUUsers.log" -Append "______________________________" | Out-File -encoding default ".\UpdateGUUsers.log" -Append         $site.Dispose()         }  if($help) { GetHelp; Continue } if($path -AND $url -AND $ou) { UpdateList -path $path -url $url -ou $ou} 

В результате работы последнего скрипта – мы получаем готовый список в sharepoint, при этом актуальный.
Если по теме статьи у вас возникли какие-то вопросы – готов ответить. Спасибо за внимание.

ссылка на оригинал статьи http://habrahabr.ru/post/168997/


Комментарии

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

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