# Аргументы командной строки
Param(
	[Parameter(Mandatory=$True)]
	[string]$WebUrl # URL-адрес веб-узла, в котором существует целевой список
)

$AddressBook = "Адресная книга"
$CompanyStructure = "Структура компании"
$MSG_LINE = "--------------------------------------------------------------------"

function StartProcess
{
	# Загружаем ActiveDirectory модуль для PowerShell
	Write-Host $MSG_LINE
	Write-Host "Загружаем модуль PowerShell для работы с Active Directory..." 
	Import-Module ActiveDirectory;
	Write-Host "Модуль PowerShell для работы с Active Directory загружен" -ForeGroundColor Green
	Write-Host $MSG_LINE
	
	
	# Загружаем SharePoint плагин для PowerShell
	Write-Host "Загружаем модуль PowerShell для работы с SharePoint..." 
	Add-PSSnapin Microsoft.SharePoint.PowerShell
	Write-Host "Модуль PowerShell для работы с SharePoint загружен" -ForeGroundColor Green
	Write-Host $MSG_LINE
	
	Write-Host "Получение объекта Web по адресу $WebUrl"
	$web = Get-SPWeb $WebUrl -ErrorAction Stop
	Write-Host "Объект Web получен" -ForeGroundColor Green
	Write-Host $MSG_LINE

	$AddressBookList = $web.Lists[$AddressBook]
	$CompanyStructureList = $web.Lists[$CompanyStructure]
	
	if($AddressBookList -eq $null)
	{
		Write-Host "Список $AddressBook не найден" -ForeGroundColor Red
	}
	else
	{
		if($CompanyStructureList -eq $null)
		{
			Write-Host "Список $CompanyStructure не найден" -ForeGroundColor Red
		}
		else
		{
			Write-Host "Списки $AddressBook и $CompanyStructure найдены. Начинаем наполнение списков данными из Active Directory" -ForeGroundColor Green

			# Получаем список всех пользователей, учётная запись которых включена
			Write-Host $MSG_LINE
			Write-Host "Получаем список всех пользователей Active Directory, учетная запись которых включена"
			$users = Get-ADUser -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)" -Properties Name,Surname,DisplayName,EmailAddress,Department,Manager,Company,Title,telephoneNumber,HomePhone,MobilePhone,Fax,StreetAddress,City,State,PostalCode,Country,Office,thumbnailPhoto,DistinguishedName -ResultSetSize 999999999 -ResultPageSize 999999999 -ErrorAction Stop
			Write-Host "Cписок пользователей получен" -ForeGroundColor Green
			
			$addressBookUsersBySID = @{ };
			foreach($addressBookUser in $AddressBookList.Items)
			{
                $userlookupValue = New-Object Microsoft.SharePoint.SPFieldUserValue($web, $addressBookUser["Пользователь"]);
                $nameId = $userlookupValue.User.UserId.NameId;
                
                if($nameId -eq $null)
                {
                    Write-Host $("В адресной книге найден элемент с незаполненным полем Пользователь с id = " + $addressBookUser.ID + " " + $addressBookUser.Title) -ForeGroundColor DarkYellow
                    continue
                }
                Try
                {
		            $addressBookUsersBySID.Add($nameId.ToUpper(), $addressBookUser);
                }
                Catch [System.ArgumentException]
                {
                    Write-Host $("Произошла ошибка при просмотре адресной книги " + $error[0] + " ИД элемента " + $addressBookUser.ID) -ForeGroundColor Red
                }
			}
			
			$departmentUsersByDepartmentTitle = @{ };
			$departmentTitleToIDDict = @{ };
			
			foreach($exitingDepartment in $CompanyStructureList.Items)
			{
				Write-Host ("Найдено подразделение " + $exitingDepartment.Title) -ForeGroundColor Green
				$departmentTitleToIDDict.Add($exitingDepartment.Title, $exitingDepartment.ID);
			}
			
			$usersAccountDict = @{ };
			$usersAccountNameToIDDict = @{ };
			
			# Сначала создаем всех пользователей и все подразделения
			foreach($user in $users)
			{
				#Write-Host ("Добавление в список контактов учетной записи " + $user.DisplayName + " " + $user.SamAccountName) -ForeGroundColor Yellow
				if(-not [string]::IsNullOrEmpty($user.Department))
				{
					if(-not $departmentUsersByDepartmentTitle.ContainsKey($user.Department))
					{
						$departmentUsersByDepartmentTitle.Add($user.Department, @($user));
						
                        if($departmentTitleToIDDict.ContainsKey($user.Department))
                        {
                            $newDepartmentID = $departmentTitleToIDDict[$user.Department];
                        }
                        else
                        {
                            Write-Host ("Создание подразделения " + $user.Department) -ForeGroundColor Cyan
						    $newDepartmentID = CreateDepartment $CompanyStructureList $user;
                            $departmentTitleToIDDict.Add($user.Department, $newDepartmentID);
                        }
					}
					else
					{
						$departmentUsersByDepartmentTitle[$user.Department] += $user;
					}
				}
				
				$usersAccountDict.Add($user.DistinguishedName, $user);
				$newAccountID = EnsureUserID $web $user $AddressBookList $addressBookUsersBySID $departmentTitleToIDDict;
				$usersAccountNameToIDDict.Add($user.DistinguishedName, $newAccountID);
			}
			
			Write-Host "Подразделения и контакты добавлены" 
			Write-Host $MSG_LINE
			Write-Host "Заполняем иерархию подразделений"
			
			#$countContacts = 0;
			#foreach($department in $departmentUsersByDepartmentTitle)
			#{
			#	$countContacts += $department.Length;
			#}
			
			$rootDepartmentID = CreateRootDepartment $CompanyStructureList;
			
			# Заполняем иерархию подразделений
			foreach($user in $users)
			{
				$childDepartment = $user.Department;
				$parentDepartment = $null;
				
				if(-not [string]::IsNullOrEmpty($user.Manager) -and $usersAccountDict.ContainsKey($user.Manager))
				{
					$manager = $usersAccountDict[$user.Manager];
					$parentDepartment = $manager.Department;
					
					Write-Host "Родительское подразделение $parentDepartment"
					Write-Host "Дочернее подразделение $childDepartment"
					
					if(-not [string]::IsNullOrEmpty($childDepartment) -and $departmentTitleToIDDict.ContainsKey($childDepartment))
					{
						$childDepartmentItem = $CompanyStructureList.GetItemById($departmentTitleToIDDict[$childDepartment]);
						$childDepartmentItem["Численность"] = $departmentUsersByDepartmentTitle[$childDepartment].Length;
						
						if(-not [string]::IsNullOrEmpty($parentDepartment) -and $departmentTitleToIDDict.ContainsKey($parentDepartment))
						{
							if($childDepartmentItem.ID -ne $departmentTitleToIDDict[$parentDepartment])
							{
								Write-Host "$parentDepartment <- $childDepartment" -ForeGroundColor Gray
								$childDepartmentItem["Родительское подразделение"] = $departmentTitleToIDDict[$parentDepartment];
							}
						}
						if($parentDepartment -eq $childDepartment) 
						{
							#$childDepartmentItem["Руководитель"] = GetUserIDByAccountName $web $manager;
                            $childDepartmentItem["Фамилия руководителя"] = $usersAccountNameToIDDict[$manager.DistinguishedName];
						}
						
						$childDepartmentItem.Update();
					}
				}
				
				if(-not [string]::IsNullOrEmpty($childDepartment) -and $departmentTitleToIDDict.ContainsKey($childDepartment))
				{
					if([string]::IsNullOrEmpty($parentDepartment) -or -not $departmentTitleToIDDict.ContainsKey($parentDepartment))
					{
						Write-Host "Организация <- $childDepartment" -ForeGroundColor Magenta
						$childDepartmentItem = $CompanyStructureList.GetItemById($departmentTitleToIDDict[$childDepartment]);
						$childDepartmentItem["Родительское подразделение"] = $rootDepartmentID;
						$childDepartmentItem.Update();
					}
				}
				
			}
			
			Write-Host $MSG_LINE
		}
	}

	$web.Dispose()
}

function CreateRootDepartment($CompanyStructureList)
{
	$rootDepartment = $CompanyStructureList.AddItem();
	$rootDepartment["Title"] = "Организация";
	$rootDepartment.Update();
	
	return $rootDepartment.ID;
}

function EnsureUserID($web, $user, $AddressBookList, $addressBookUsersBySID, $departmentTitleToIDDict)
{
	if($addressBookUsersBySID.ContainsKey($user.SID.ToString().ToUpper()))
	{	
        Write-Host ("Обновление контакта учетной записи " + $user.DisplayName + " " + $user.SamAccountName) -ForeGroundColor Magenta
        $newContact = $addressBookUsersBySID[$user.SID.ToString().ToUpper()];
    }
	else
    {
        Write-Host ("Добавление в список контактов учетной записи " + $user.DisplayName + " " + $user.SamAccountName) -ForeGroundColor Yellow
		$newContact = $AddressBookList.AddItem();
    }
	
	$newContact["Фамилия"] 								= $user.Surname;
	$newContact["Полное имя"] 							= $user.DisplayName;
	if([string]::IsNullOrEmpty($user.DisplayName))
	{
		$nameParts = $user.DisplayName -split '\s+';
		if($nameParts.Length -ge 2)
		{
			$newContact["Имя"] 							= $nameParts[1];
		}
		else
		{
			$newContact["Имя"] 							= $nameParts[0];
		}
	}
	
	$newContact["Адрес электронной почты"] 				= $user.EmailAddress;
	$newContact["Организация"] 							= $user.Company;
	$newContact["Должность"] 							= $user.Title;
	$newContact["Рабочий телефон"] 						= $user.telephoneNumber;
	$newContact["Домашний телефон"] 					= $user.HomePhone;
	$newContact["Мобильный телефон"] 					= $user.MobilePhone;
	$newContact["Номер факса"] 							= $user.Fax;
	$newContact["Адрес"] 								= $user.StreetAddress;
	$newContact["Город"] 								= $user.City;
	$newContact["Республика, область или край"] 		= $user.State;
	$newContact["Индекс"] 								= $user.PostalCode;
	$newContact["Страна или регион"]					= $user.Country;
	$newContact["Веб-страница"] 						= $user.HomePage;
	$newContact["Примечания"] 							= "";
	$newContact["Расположение"] 						= $user.Office;
	if([string]::IsNullOrEmpty($user.Surname))
	{
		$newContact["Пол"] 								= "мужской";
	}
	else 
	{
		if($user.Surname.EndsWith("ва"))
		{
			$newContact["Пол"]							= "женский";
		}
		else
		{
			$newContact["Пол"]							= "мужской";
		}
	}
	# $newContact["Фотография контакта"] 					= $user.thumbnailPhoto;
	
	$newContact["Отображать на странице подразделения"] 	= $true;

	$newContact["Пользователь"] 						= GetUserIDByAccountName $web $user;
	
	if(-not [string]::IsNullOrEmpty($user.Department))
	{
		$newContact["Подразделение"] 					= $departmentTitleToIDDict[$user.Department];
	}
	
	$newContact.Update();
	
	return $newContact.ID;
	
}

function CreateDepartment($CompanyStructureList, $user)
{
	$newDepartment = $CompanyStructureList.AddItem();
	$newDepartment["Title"] = $user.Department;
	$newDepartment.Update();
	return $newDepartment.ID;
}

function GetUserIDByAccountName($web, $user)
{
	$spuser = $null;
	Try
	{
		$spuser = $web.EnsureUser($user.SamAccountName);
	}
	Catch [System.Exception]
	{
		$username = $user.SamAccountName;
	}
	if($spuser -eq $null)
	{
		Write-Host "На портале не найден пользователь $username, существующий в Active Directory"
		return $null;
	}
	else
	{
		return $spuser.ID;
	}
}

StartProcess