######################################################################### ####### # SyncXLS2AD # Версия 2.36xls 25.12.2011

advertisement
#########################################################################
#######
# SyncXLS2AD
# Версия 2.36xls 25.12.2011
#
# Описание: Синхронизация учётных записей пользователей Active Directory
с данными по сотрудникам Компании из документа MS Office Excel (.xlsx)
#
# Илгиз Мамышев (c) 2011
# http://imamyshev.wordpress.com
#########################################################################
#######
# Измените переменные под текущую инфраструктуру
$XLSSource = "\\ad.demo.ru\dfs\HR\Сотрудники\Сотрудники Компании.xlsx";
$ADSearchBase = "DC=AD,DC=WEBZAVOD,DC=RU";
$SharePath="\\ad.demo.ru\dfs$\Deploy\SyncXLS2AD"; # Общая папка для
скрипта, журнала, временных файлов
$SmtpServer = "wz-exch01.ad.demo.ru"
# Почтовый сервер
$SmtpFrom = "SyncXLS2AD@demo.ru"
$SmtpTo = "logs@demo.ru"
# НИЖЕ ЭТОЙ СТРОКИ СКРИПТ НЕ ИЗМЕНЯТЬ!
$ScriptName = "SyncXLS2AD";
$Count = 1; $Count2 = 1; $Count3 = 1; $Count4 = 1; # переменные для
различных счетчиков
$script:GETXLSData_recommend_Counter = 0;
$RecomTextLN = @();
$RecomTextDSBL = @();
$GETXLSData_recommend = @();
$LogFile = "$SharePath\$ScriptName"+".log"
# Файл журнала
работы скрипта
$RulesFile = "$SharePath\$ScriptName"+"_RULES.txt" # Файл с правилами
работы скрипта
$Subject = "Актуализация данных в Active Directory - РЕКОМЕНДАЦИИ
АДМИНИСТРАТОРУ"
$VerbosePreference = "Continue" #Разрешить вывод сообщений Write-Verbose
(для проведения отладки)
$VerbosePreference = "SilentlyContinue" #Запретить вывод сообщений WriteVerbose (для нормальной работы)
#========================================================================
=======
"=====================================================================" >
$RulesFile
"СИНХРОНИЗАЦИЯ УЧЕТНЫХ ЗАПИСЕЙ ПОЛЬЗОВАТЕЛЕЙ ACTIVE DIRECTORY" >>
$RulesFile
"С ДАННЫМИ ПО СОТРУДНИКАМ КОМПАНИИ ИЗ EXCEL СПИСКА СОТРУДНИКОВ" >>
$RulesFile
"" >> $RulesFile
"`t`t`tО С Н О В Н Ы Е
П Р А В И Л А" >> $RulesFile
"" >> $RulesFile
"1. НАПРАВЛЕНИЕ СИНХРОНИЗАЦИИ EXCEL (.xlsx) ФАЙЛ - > ACTIVE DIRECTORY" >>
$RulesFile
"Требования к Excel файлу-Источнику:" >> $RulesFile
"- выполняется чтение только первого листа документа;" >> $RulesFile
"- первая строка воспринимается как заголовок документа с именами
колонок, очерёдность колонок значения не имеет;" >> $RulesFile
"- обязательные имена колонок и пример\формат заполнения" >> $RulesFile
"ИМЯ КОЛОНКИ
ФОРМАТ
НАЗНАЧЕНИЕ" >> $RulesFile
"EmplID
123456
Табельный номер" >> $RulesFile
"Surname
Иванов
Фамилия" >> $RulesFile
"GivenName Иван
Имя" >> $RulesFile
"Middlename Иванович
Отчество" >> $RulesFile
#"BirthDay 12.12.1234 День рождения" >> $RulesFile
"Title
Инженер
Должность" >> $RulesFile
"Department ДППР
Подразделение" >> $RulesFile
"Company
ООО 'Марс' Компания" >> $RulesFile
"Office
123
Кабинет" >> $RulesFile
"OfficePhone
+7(846)1234567
Рабочий телефон" >> $RulesFile
"IPPhone
123
Внутренний телеон" >> $RulesFile
"MobilePhone
+7(937)1234567
Мобильный телефон" >> $RulesFile
"Manager
Пётр Петров FullName учётной записи Менеджера в Acrive
Directory" >> $RulesFile
"Dismissed 12.12.1234 Дата увольнения" >> $RulesFile
"- все поля должны быть текстовыми, без форматирования" >> $RulesFile
"2. СОЕДИНЕНИЕ данных Excel и Active Directory выполняется по 'ИМЯ
ФАМИЛИЯ' (поле 'FullName') или по табельному номеру (поле
'EmployeeNumber')" >> $RulesFile
"3. Поля учетной записи пользователя домена, подлежащие обновлению:" >>
$RulesFile
"- Общие\Фамилия" >> $RulesFile
"- Общие\Имя" >> $RulesFile
"- Общие\Инициалы" >> $RulesFile
"- Общие\Офис" >> $RulesFile
"- Общие\Телефон" >> $RulesFile
"- EmployeeNumber (Табельный номер)" >> $RulesFile
"- Организация\Должность" >> $RulesFile
"- Организация\Отдел" >> $RulesFile
"- Организация\Организация" >> $RulesFile
"- Организация\Менеджер" >> $RulesFile
"- Телефоны\Мобильный" >> $RulesFile
"- Телефоны\IP телефон" >> $RulesFile
"4. В случае изменения полей для учетной записи пользователя, найденного
в Excel файле, будут обновлены только изменившиеся поля." >> $RulesFile
"5. В случае изменения фамилии сотрудника, если учетная запись
пользователя ранее была синхронизирована и было заполнено поле
EmployeeNumber (Табельный номер)," >> $RulesFile
"в результате синхронизации будет выдана рекомендация по корректировке
учетной записи пользователя." >> $RulesFile
"6. Если сотрудник уволен, - выводимое имя в свойствах учетной записи
пользователя будет откорректировано (дописано '- уволен..')." >>
$RulesFile
"и будет выдана рекомендация по отключению учетной записи." >> $RulesFile
"7. Отключенные учетные записи не обновляются." >> $RulesFile
"8. Все произведенные изменения в Active Directory журналируются." >>
$RulesFile
"9. Рекомендации по ручной корректировке Active Directory отправляются
электронным письмом." >> $RulesFile
"" >> $RulesFile
"Системный инженер И.Мамышев" >> $RulesFile
"====================================================================="
>> $RulesFile
#=== ФУНКЦИИ
#========================================================================
=======
#=== Получить данные сотрудника по Имени и Фамилии
#=== Результат $null в случае ошибки или отсутствия данных для вывода
#=== В случае положительного результата - возврат ОДНОЙ строки с данными
#========================================================================
=======
function Get-XLS_Data ([string] $full_name = $null, [string]
$EmployeeNumber = $null)
{
$Result = new-Object System.Collections.ArrayList;
if ($full_name -ne $null)
{
#=== Разбор FULL_NAME. Выделим только первые ДВА слова (Имя и
Фамилия). Если меньше - не принимаем к обработке. Если больше - усекаем
что больше первых 2-х слов.
Write-Verbose "Строка 'Имя Фамилия' ДО обработки:
`t`t$full_name"
if ($full_name.split(" ").Count -lt 2) {Write-Verbose
"Передана некорректная строка в качестве Имени Фамилии"; return $false};
$full_name.split(" ") | ForEach-Object -begin{$c=0;
$full_name=""} -process{$c++; if($c -lt 2) {$full_name += $_+" "}; if($c
-eq 2) {$full_name += $_} }
Write-Verbose "Строка 'Имя Фамилия' ПОСЛЕ обработки:
`t$full_name";
# Делаем выборку данных о сотруднике по Имени Фамилии
($full_name)
$Result = ( Import-Csv -Path $script:CSVSource -Delimiter ";" |
Where-Object {(($_.GivenName).Trim()+" "+($_.Surname).Trim()) -eq
$full_name} );
}elseif($EmployeeNumber -ne $null)
{
# Делаем выборку данных о сотруднике по Табельному Номеру
($EmployeeNumber)
$Result = ( Import-Csv -Path $script:CSVSource -Delimiter ";"
| Where-Object {$_.EmplID -eq $EmployeeNumber} );
}else{ Write-Verbose "Не переданы Имя и Фамилия или Табельный номер
в качестве параметра!"; return $null; };
# Обрабатываем результат
if ($Result -ne $null)
{
$Result | ForEach-Object -Begin {$i=0} -Process {$i++} -End
{$i};
if ($i -gt 1)
{
Write-Verbose $Result;
Write-Verbose "Результатов больше чем 1. Прерываем
процедуру.";
return $null;
};
}else
{
Write-Verbose "Нет данных для вывода по запрошенному Имя
Фамилия ($full_name)!";
$script:GETXLSData_recommend_Counter++;
return $null;
};
# В результирующем наборе ОДИН сотрудник и его данные
# Обработаем данные (срежем с концов строк возможные пробелы и
точки)
$Result.Surname = $Result.Surname.Trim();
$Result.GivenName = $Result.GivenName.Trim();
$Result.MiddleName = $Result.MiddleName.Trim();
$Result.Title = $Result.Title.Trim();
$Result.Title = $Result.Title.TrimEnd(".");
$Result.Department = $Result.Department.Trim();
$Result.Department = $Result.Department.TrimEnd(".");
$Result.Company = $Result.Company.Trim();
$Result.Company = $Result.Company.TrimEnd(".");
$Result.OfficePhone = $Result.OfficePhone.Trim();
$Result.IPPhone = $Result.IPPhone.Trim();
$Result.MobilePhone = $Result.MobilePhone.Trim();
$Result.Manager = $Result.Manager.Trim();
$Result.Email = $Result.Email.Trim();
if ($Result.Dismissed.Length -le 8) {$Result.Dismissed = $null; }
else {$Result.Dismissed = Get-Date($Result.Dismissed) -Format
"dd.MM.yyyy"}; # Дата увольнения
return $Result
}
#========================================================================
=======
#=== Конвертирование файла формата .XLSX в файл формата .CSV
#=== без использования ПО MS Office Excel
#=== Вызов функции: convertXLSXtoCSV "C:\file1.xlsx" [sheet1|sheet2|..]
#=== На выходе одноименный файл в формате CSV: C:\file1.csv
#========================================================================
=======
function convertXLSXtoCSV ([string] $xlspath, $sheet = "sheet1")
{
function INTto26
{
param ([int]$x)
$m = $x % 26
if($x -gt 0 -and $m -eq 0){$m = 26}
if(($x-$m) -gt 0)
{
$d = ($x-$m)/26
$dummy = 0
intto26 $d
}
$m
}
function STRINGto26INT ([string]$s)
{
([int[]][char[]]$s.toupper())[-1..-$s.length] | %{$_-64} |
%{$m = 1}{$_*$m;$m*=26} | Measure-Object -Sum |
Select-Object -ExpandProperty sum
}
function Int26toSTRING ([int]$i)
{
$ofs = ""
[string][char[]]((INTto26 $i) | %{$_+64})
}
$mincol = 16384
$maxcol = 1
$minrow = [int]::MaxValue
$maxrow = 1
$shellApplication = new-object -com shell.application
$file = Get-Item $xlspath
$destination = Split-Path $xlspath
if(!(Test-Path "$destination\temp")){ [void] (New-Item -Path
$destination -Name temp -ItemType directory) }
Rename-Item $xlspath "$xlspath.zip"
$zipPackage = $shellApplication.NameSpace("$xlspath.zip")
$destinationFolder =
$shellApplication.NameSpace("$destination\temp")
$destinationFolder.CopyHere($zipPackage.Items().item(2))
#
$sharedstr = ([xml] (Get-Content
"$destination\temp\xl\sharedStrings.xml" -Encoding utf8)).sst.si |
Select-Object -ExpandProperty t | %{ if($_ -is
[System.Xml.XmlElement]){$_."#text"}else{$_} }
#
$sh = [xml](Get-Content
"$destination\temp\xl\worksheets\$sheet.xml" -Encoding utf8)
$basedata = $sh.worksheet.sheetData | %{$_.row} | %{$_.c} | %{
$col = $_.r -replace "\d+",""
if((STRINGto26INT $col) -gt $maxcol){$maxcol = (STRINGto26INT
$col)}
if((STRINGto26INT $col) -lt $mincol){$mincol = (STRINGto26INT
$col)}
$row = $_.r -replace "[a-z]+",""
if([int]$row -gt [int]$maxrow){$maxrow = $row}
if([int]$row -lt [int]$minrow){$minrow = $row}
$value = if($_.t -eq "s"){$sharedstr[($_.v)]}elseif($_.t -ne
"E"){$_.v}
New-Object -TypeName PSObject -Property @{col = $col; row =
$row; value = $value}
}
#
Remove-Item "$destination\temp" -Confirm:$false -Force -Recurse
Rename-Item "$xlspath.zip" $xlspath
#
$h = @{}
$mincol..$maxcol | %{Int26toSTRING $_} | %{$h.$_ = ""}
$th = @{}
$minrow..$maxrow | %{$th.$_ = New-Object -TypeName psobject Property $h}
$basedata | %{ ($th.([int]$_.row)).($_.col) = $_.value }
#
$th.keys | Sort-Object |%{$th.$_}|
Select-Object -Property ($mincol..$maxcol | %{Int26toSTRING $_}
) |
Export-Csv -Path ($xlspath -replace 'xlsx$',"csv") NoTypeInformation -UseCulture -Encoding utf8
}
#=== НАЧАЛО
import-module ActiveDirectory
$dtstart = Get-Date -Format "dd.MM.yyyy HH:mm:ss"
"======================================================`n
Синхронизация Active Directory с Excel-списком сотрудников`n
Источник данных (Excel-список сотрудников): " + $XLSSource + "`n
Отчет о изменениях: " + $LogFile + "`n
Начало: "+$dtstart+"`n">> $LogFile
"------------------------------------------------------" >> $LogFile
$RecomText += "РЕКОМЕНДАЦИИ по итогам Синхронизации Active Directory с
Excel-списком сотрудников: $XLSSource </br>
Отчет о произведенных изменениях в Active Directory: $LogFile </br>
Правила работы процесса синхронизации: $RulesFile </br>
Начало: $dtstart </br>
--------------------------------------------------------------------</br>
Измените свойства учетных записей в соответствии с
информацией\рекомендациями ниже, затем повторите или дождитесь следующей
синхронизации. </br>"
cls
Write-Host "Синхронизация Active Directory с Excel-списком сотрудников"
Write-Host "Пожалуйста подождите.."
# Подготовим копию файла Источника для импорта
Copy-Item $XLSSource $SharePath
$XLSSource = $SharePath + "\" + (Split-Path $XLSSource -leaf)
if (Test-Path $XLSSource)
{
# Преобразуем XLS файл в CSV
convertXLSXtoCSV $XLSSource
$CSVSource = $XLSSource -replace 'xlsx$',"csv"; # Путь к результату
convertXLSXtoCSV
}else
{
$RecomText = "Не удаётся найти файл $XLSSource. Выполнение прервано."
"ERROR: " + $RecomText >> $LogFile
Write-Host $RecomText
exit
}
# Удалим первую строку из файла (строка с именами столбцов: A,B,C,D..)
$File = Get-Content -Path $CSVSource
$File = $File[1..$($File.Count - 1)]
$File > $CSVSource
# Подготовим список учётных записей из Active Directory
$ADUsers=( Get-ADUser -Filter { (Name -like "*") } -SearchBase
$ADSearchBase -SearchScope Subtree -Properties * | Where
{$_.DistinguishedName -notlike "*Service Accounts*"} | Where
{$_.DistinguishedName -notlike "*Official Accounts*"} | Where
{$_.DistinguishedName -notlike "*Test Accounts*"} )
# Перебираем всех отобранных пользователей ActiveDirectory, пытаемся
найти данные по ним в результатах запроса к Источнику данных
$ADUsers |
ForEach-object -Begin {if($ADUsers.Count -le
0){$ADUCnt=1}else{$ADUCnt=$ADUsers.Count}; $percent=$ADUCnt/100; $c = 0;
"Будет обработано $ADUCnt учетных записей" >> $LogFile} -Process {
$c++; [int]$a = $c/$percent; Write-Progress -Activity "Идет
обработка..." -PercentComplete $a -CurrentOperation "$a% завершено" Status "Пожалуйста подождите."; #Счетчик - процент выполнения
#=== Пробуем получить данные по сотруднику по ФИ ($_.Name)
# Мы здесь даже тогда, когда поле ТАБЕЛЬНЫЙ НОМЕР заполнено, но
данные в запросе к Источнику не нашли
# Если учетная запись пользователя в AD ВЫКЛЮЧЕНА, то выходим из
цикла и идем к следующей итерации
if ([bool]($_.Enabled -eq $false)) {Write-Verbose "$_.Name
выключен, переход к следующему циклу."; return; }
$Count2++
# Запросим данные о сотруднике из Источника по Имени Фамилии
$b = New-Object System.Collections.ArrayList
$b = Get-XLS_Data($_.Name, $null)
Write-Verbose "$($_.EmployeeNumber) $($_.Name)
$($_.UserPrincipalName) Счетчик: $Count2"
if ($b -ne $null)
{
# Информация из Источника по Имя Фамилия получена, подготовим
данные
if ($b[1].Surname.Length -gt 64)
{$b[1].Surname=$b[1].Surname.SubString(0,64)}
if ($b[1].GivenName.Length -gt 64)
{$b[1].GivenName=$b[1].GivenName.SubString(0,64)}
if ($b[1].Title.Length -gt 64)
{$b[1].Title=$b[1].Title.SubString(0,64)}
if ($b[1].Department.Length -gt 64)
{$b[1].Department=$b[1].Department.SubString(0,64)}
if ($b[1].Company.Length -gt 64)
{$b[1].Company=$b[1].Company.SubString(0,64)}
if ($b[1].MiddleName.Length -gt 64)
{$b[1].MiddleName=$b[1].MiddleName.SubString(0,64)}
if ($b[1].OfficePhone.Length -gt 64)
{$b[1].OfficePhone=$b[1].OfficePhone.SubString(0,64)}
if ($b[1].IPPhone.Length -gt 64)
{$b[1].IPPhone=$b[1].IPPhone.SubString(0,64)}
if ($b[1].MobilePhone.Length -gt 64)
{$b[1].MobilePhone=$b[1].MobilePhone.SubString(0,64)}
$Initials = $b[1].GivenName[0] + "." + $b[1].MiddleName[0] +
".";
$OfficePhone = $b[1].OfficePhone + "x" + $b[1].IPPhone;
$DisplayName = $b[1].GivenName + " " + $b[1].Surname;
$Manager = $b[1].Manager;
if ( ($Manager -eq $null) -or ($Manager.Length -le 1) )
{$Manager = ""}else {$Manager = Get-ADUser -Filter {Name -eq $Manager}}
$dt = Get-Date -Format "dd.MM.yyyy HH:mm:ss";
$notes = "Синхронизировано ($ScriptName) с Источником " + $dt
#=== Подготовим параметры для Set-ADUser
$doUpdate = $false;
$Parameters = @{};
if([string]$_.Surname -ne [string]$b[1].Surname) {$Parameters["Surname"] = $b[1].Surname; $doUpdate = $true;};
if([string]$_.GivenName -ne [string]$b[1].GivenName)
{$Parameters["-GivenName"] = $b[1].GivenName; $doUpdate = $true;};
if($DisplayName.Length -ne 0) {$Parameters["-DisplayName"] =
$DisplayName};
# Если параметр изменился и он не пустой (сравниваем значение из
Источника и из AD), то будем обновлять
if( ([string]$_.Initials -ne [string]$Initials) -and
($Initials.Length -ne 0) ) {$Parameters["-Initials"] = $Initials;
$doUpdate = $true;};
if( ([string]$_.Office -ne [string]$b[1].Office) -and
($b[1].Office.Length -ne 0) ) {$Parameters["-Office"] = $b[1].Office;
$doUpdate = $true;};
if( ([string]$_.EmployeeNumber -ne [string]$b[1].EmplID) -and
($b[1].EmplID.Length -ne 0) ) {$Parameters["-EmployeeNumber"] =
$b[1].EmplID; $doUpdate = $true;};
if( ([string]$_.Title -ne [string]$b[1].Title) -and
($b[1].Title.Length -ne 0) ) {$Parameters["-Title"] = $b[1].Title;
$doUpdate = $true;};
if( ([string]$_.Department -ne [string]$b[1].Department) -and
($b[1].Department.Length -ne 0) ) {$Parameters["-Department"] =
$b[1].Department; $doUpdate = $true;};
if( ([string]$_.Company -ne [string]$b[1].Company) -and
($b[1].Company.Length -ne 0) ) {$Parameters["-Company"] = $b[1].Company;
$doUpdate = $true;};
if( ([string]$_.OfficePhone -ne [string]$OfficePhone) -and
($OfficePhone.Length -ne 0) ) {$Parameters["-OfficePhone"] =
$OfficePhone; $doUpdate = $true;};
if( ([string]$_.MobilePhone -ne [string]$b[1].MobilePhone) -and
($b[1].MobilePhone.Length -ne 0) ) {$Parameters["-MobilePhone"] =
$b[1].MobilePhone; $doUpdate = $true;};
if( ([string]$_.Manager -ne [string]$Manager.DistinguishedName) and ($b[1].Manager.Length -ne 0) ) {$Parameters["-Manager"] =
$Manager.DistinguishedName; $doUpdate = $true;};
# Некоторые параметры можем записать\обновить только через
Add, Replace
$Replace = @{Info=$notes;}
if( ([string]$_.ipPhone -ne [string]$b[1].IPPhone) -and
($b[1].IPPhone.Length -ne 0) ) {$Replace = $Replace +
@{ipPhone=$b[1].IPPhone}; $doUpdate = $true;};
if($Replace.Count -gt 0) {$Parameters["-Replace"] = $Replace;};
# Если параметр пустой и он изменился (сравниваем значение из
Источника и из AD), то будем его удалять
$Remove = @{}
if( ([string]$_.Office -ne [string]$b[1].Office) -and
($b[1].Office.Length -eq 0) ) {$Remove = $Remove +
@{physicalDeliveryOfficeName=$_.Office}; $doUpdate = $true;};
if( ([string]$_.EmployeeNumber -ne [string]$b[1].EmplID) -and
($b[1].EmplID.Length -eq 0) ) {$Remove = $Remove +
@{employeeNumber=$_.EmployeeNumber}; $doUpdate = $true;};
if( ([string]$_.Title -ne [string]$b[1].Title) -and
($b[1].Title.Length -eq 0) ) {$Remove = $Remove + @{title=$_.Title};
$doUpdate = $true;};
if( ([string]$_.Department -ne [string]$b[1].Department) -and
($b[1].Department.Length -eq 0) ) {$Remove = $Remove +
@{department=$_.Department}; $doUpdate = $true;};
if( ([string]$_.Company -ne [string]$b[1].Company) -and
($b[1].Company.Length -eq 0) ) {$Remove = $Remove +
@{company=$_.Company}; $doUpdate = $true;};
if( ([string]$_.OfficePhone -ne [string]$OfficePhone) -and
($OfficePhone.Length -eq 0) ) {$Remove = $Remove +
@{telephoneNumber=$_.OfficePhone}; $doUpdate = $true;};
if( ([string]$_.MobilePhone -ne [string]$b[1].MobilePhone) -and
($b[1].MobilePhone.Length -eq 0) ) {$Remove = $Remove +
@{mobile=$_.MobilePhone}; $doUpdate = $true;};
if( ([string]$_.Manager -ne [string]$Manager.DistinguishedName) and ($b[1].Manager.Length -eq 0) ) {$Remove = $Remove +
@{manager=$_.Manager}; $doUpdate = $true;};
if( ([string]$_.ipPhone -ne [string]$b[1].IPPhone) -and
($b[1].IPPhone.Length -eq 0) ) { $Remove = $Remove +
@{ipPhone=$_.ipPhone}; $doUpdate = $true;};
if($Remove.Count -gt 0) {$Parameters["-Remove"] = $Remove;}
if($doUpdate -eq $true)
{
# Один или несколько параметров учётной записи
изменились, требуется обновление
Try
{
$_ | Set-ADUser @Parameters;
}
Catch
{ # Catch Errors
Write-Verbose $_
Write-Verbose "!!! Ошибка Set-ADUser, переходим к
следующему циклу.";
return;
}
"" >> $LogFile;
"" + $Count + ". Обновлены свойства: " +
$_.DistinguishedName >> $LogFile;
"Было`t=>LastName:" + $_.Surname + ",`tFirstName:" +
$_.GivenName + ",`tInitials:" + $_.Initials + ",`tOffice:" + $_.Office +
",`tEmployeeNumber:" + $_.EmployeeNumber + ",`tTitle:" + $_.Title +
",`tDepartment:" + $_.Department + ",`tCompany:" + $_.Company +
",`tOfficePhone:" + $_.OfficePhone+ ",`tMobilePhone:" + $_.MobilePhone +
",`tIPPhone:" + $_.ipPhone + ",`tManager:" + $_.Manager >> $LogFile
"Стало`t=>LastName:" + $b[1].Surname + ",`tFirstName:" +
$b[1].GivenName + ",`tInitials:" + $Initials + ",`tOffice:" +
$b[1].Office + ",`tEmployeeNumber:" + $b[1].EmplID + ",`tTitle:" +
$b[1].Title + ",`tDepartment:" + $b[1].Department + ",`tCompany:" +
$b[1].Company + ",`tOfficePhone:" + $OfficePhone + ",`tMobilePhone:" +
$b[1].MobilePhone + ",`tIPPhone:" + $b[1].IPPhone + ",`tManager:" +
$Manager.DistinguishedName >> $LogFile
$Count++
}
$dt = Get-Date
$dt = $dt.ToShortDateString()
if( ($b[1].Dismissed -ne $null)-and($dt -gt $b[1].Dismissed)
)
{
# Сотрудник уволен. Обновим Выводимое имя пользователя
$NewDisplayName = $b[1].GivenName + " " + $b[1].Surname
+ " - уволен(а) с " + $b[1].Dismissed
$_ | Set-ADUser -DisplayName $NewDisplayName
"" + $_.DistinguishedName + "`n Сотрудник уволен.
Выводимое Имя сменено на: " + $NewDisplayName >> $LogFile
# Отключим учетную запись пользователя, если она не
отключена
if ([bool]($_.Enabled -eq $true) )
{
if ( $_.LastLogonDate -eq $null ) {$LL = "Нет
данных"}else{$LL = $_.LastLogonDate}
}
$RecomTextDSBL += (new-object psobject | add-member
noteproperty "№" "$Count4" -passthru | add-member noteproperty "Full
Name" ($b[1].GivenName + " " + $b[1].Surname + " уволен(а) с " +
$b[1].Dismissed) -passthru | add-member noteproperty "Last logon" $LL passthru | add-member noteproperty "Department" $_.Department -passthru)
#$_ | Set-ADUser -Enabled $false; $RecomTextDSBL +=
"Действие: Отключена учетная запись $_.DistinguishedName`n"
$Count4++
}
}elseif($b -eq $null)
{
# Информация в Источнике ЗАПРАШИВАЛАСЬ по Имя Фамилия и НЕ
БЫЛА ПОЛУЧЕНА, готовим инфу для лога рекомендаций
if ([bool]($_.Enabled -eq $true) )
{
if ( $_.LastLogonDate -eq $null ) {$LL = "Нет
данных"}else{$LL = $_.LastLogonDate}
}
$GETXLSData_recommend += (new-object psobject | add-member
noteproperty "№" "$GETXLSData_recommend_Counter" -passthru | add-member
noteproperty "DistinguishedName" $_.DistinguishedName -passthru | addmember noteproperty "Last logon" $LL -passthru | add-member noteproperty
"Department" $_.Department -passthru)
# Не нашли по Имя Фамилия и Если заполнено поле табельный
номер, то пробуем получить из Источника данные сотрудника по табельному
номеру
if ($_.EmployeeNumber.Length -gt 0)
{
$b2 = Get-XLS_Data($null, $_.EmployeeNumber);
if($b2 -ne $null)
{
$Initials = $b2[1].GivenName[0] + "." +
$b2[1].MiddleName[0] + "."
Write-Verbose "$($_.EmployeeNumber) $($_.Name)
$($_.UserPrincipalName)"
if( ([string]$b2[1].Surname -ne
[string]$_.Surname)-and([string]$b2[1].GivenName -eq
[string]$_.GivenName)-and([string]$Initials -eq [string]$_.Initials) )
{
# Если нашли данные в Источнике по
табельному номеру, ИМЯ и ИНИЦИАЛЫ совпадают , а ФАМИЛИЯ в учётной записи
АД НЕ совпадает с ФАМИЛИЕЙ из Источника, то
# Готовим рекомендацию - СМЕНИЛАСЬ ФАМИЛИЯ
ПОЛЬЗОВАТЕЛЯ
$RecomTextLN += (new-object psobject | add-member
noteproperty "№" "$Count3" -passthru | add-member noteproperty
"EmployeeNumber" $_.EmployeeNumber -passthru | add-member noteproperty
"Было (AD)" ($_.Surname + " " + $_.GivenName + " " + $_.Initials) passthru | add-member noteproperty "Стало (Excel)" ($b2[1].Surname + " "
+ $b2[1].GivenName + " " + $Initials) -passthru)
$Count3++
}
}else
{
#=== Записанный в учетке Табельный номер не найден
в Источнике, удалим Таб.номер как неверный
Write-Verbose "Табельный номер, указанный в AD не
существует в Источнике!"
Set-ADUser -Identity $_.DistinguishedName EmployeeNumber $null
"Табельный номер , указанный в AD не существует в
Источнике. Значение будет удалено!" >> $LogFile
"Было`t=> `tDistinguishedName:`t" +
$_.DistinguishedName + "`tEmployeeNumber:`t" + $_.EmployeeNumber >>
$LogFile
}
}
}
} # ForEach-object -Process
#================================================================
"Обновлено " + ($Count - 1) + " учетных записей пользователей Active
Directory" >> $LogFile
$dt = Get-Date -Format "dd.MM.yyyy HH:mm:ss"
"Конец: "+$dt >> $LogFile
# Готовим тексты рекомендаций
if ($RecomTextLN.Length -gt 0)
{
$RecomText += "-------------------------------------------------------------------- </br>"
$RecomText += "Список сотрудников, у которых изменилась
фамилия.</br>"
$RecomText += "Если рекомендации в части ИЗМЕНЕНИЯ ФАМИЛИИ неверны
- удалите содержимое поля 'EmployeeNumber' свойств учетной записи
пользователя. </br>"
$RecomText += ($RecomTextLN | ConvertTo-Html)
}
if ($RecomTextDSBL.Length -gt 0)
{
$RecomText += "-------------------------------------------------------------------- </br>"
$RecomText += "Следующие сотрудники уволены, - рекомендуется
отключить уч. записи: </br>"
$RecomText += ($RecomTextDSBL | ConvertTo-Html)
Write-Host $RecomTextDSBL
}
if ($GETXLSData_recommend.Length -gt 0)
{
$RecomText += "-------------------------------------------------------------------- </br>"
$RecomText += "Следующие Имя Фамилия не были обнаружены при запросе
к Источнику, возможно их необходимо откорректировать: </br>"
$RecomText += ($GETXLSData_recommend | ConvertTo-Html)
}
$RecomText += "Конец: "+$dt + "`n"
Write-Progress -Activity "Working..." -Completed -Status "All done."
#Отображение индикатора выполнения завершим. Пропадет с экрана.
#=== Отправка EMail
Write-Verbose "Создаем объекты SmtpClient и MailMessage"
$SmtpClient = New-Object System.Net.Mail.SmtpClient
$Message = New-Object System.Net.Mail.MailMessage
$SmtpClient.Host = $SmtpServer
$Message.IsBodyHtml = $True
$Message.Body = $RecomText
$Message.Subject = $Subject
$Message.From = $SmtpFrom
[string[]]$To = $SmtpTo
[System.IO.FileInfo[]]$Attachment=@() #
[System.IO.FileInfo[]]$Attachment= (dir c:\*.txt)
Write-Verbose "Создаем и добавляем вложения"
$Attachment | ForEach-Object {
$a = New-Object System.Net.Mail.Attachment($_.fullname)
$Message.Attachments.Add($a)
}
Write-Verbose "Добавляем получателей"
$To | ForEach-Object {$Message.To.Add($_)}
Write-Verbose "Отправляем сообщение"
$smtpclient.Send($Message)
$Message.Dispose()
#
Write-Host "Синхронизация завершена."
Write-Host "Отчет о произведенных изменениях в Active Directory:
$LogFile"
Write-Host "Рекомендации по ручной корректировке базы данных AD высланы
на $SmtpTo"
Write-Verbose "Удаляем временные файлы"
#Remove-Item $CSVSource
#Remove-Item ($SharePath + "\" + (Split-Path $XLSSource -leaf))
#=== КОНЕЦ
Download