Pull to refresh

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

Reading time9 min
Views25K
     Бывает так — что в крупной организации, подчиненной сложным корпоративным правилам — возникает несколько точек проникновения информации из реального мира в мир 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, при этом актуальный.
Если по теме статьи у вас возникли какие-то вопросы – готов ответить. Спасибо за внимание.
Tags:
Hubs:
+2
Comments9

Articles

Change theme settings