Update Active Directory credentials
Many people remember that feeling when your company expands to those dimensions when working groups are insufficient, and raised the first Active Directory domain is: "Oh, now everything will be as it should!" But no, domain quietly grows, creating new accounts, locked, old, added, deleted, computers, girls marry, change their names and, in the end, the database directory looks like full of seams. In this topic we will establish the connection between the base Active Directory and personnel system of the enterprise and also to create a mechanism to maintain employee data in AD to date.
First, we describe requirements that we must submit to the accounts of employees. And these requirements we will try to estimate, based on the needs of the user. It is no secret that many enterprise systems using authentication via Active Directory to display in their adminco, and just in the course of work often use a variety of field AD account: Sharepoint, Citrix, and many others. As example I'll take is known to all, MS Outlook, but not completely, but only its address book, which draws its data directly from Active Directory.

Using what user? We have in the organization, he often looks for named phone, email address and the name of the unit. Of course, good fill out and the address information, but due to the fact that the topic we have about conjunction with an abstract of the personnel system, we addresses and phone numbers leave out.
First, we give the list of fields that we wish to take from the personnel system, we will:
the
Naturally, in order to associate a person from the HR system and the person from Active Directory, you must have an identifier to link these two records. Usually this ID is the personnel number of the employee, it is assigned to when applying for a job and never changes, however, I have met with situations where the employee ID is not static, in this case the identifier should be invented.
User information Active Directory is not limited to information that can be seen in Active Directory Users and Computers (ADUC established reduction), and very far from being exhausted. In fact, the user object has a trillion attributes, and these attributes can even be added by the administrator of the scheme. For example, there is such attribute as carLicense containing information about driving license, or drink characterizing favorite beverage of the user. In General, Microsoft has provided a lot.
To use my example, I will attributes employeeID to store the user ID, and flags, for what it is, I tell you later.
Also to populate the fields user, we will use the attributes:
the
So, our app will work this way:
theto Enumerate accounts that have filled employeeID
the to Search for in the personnel system for each account of the changed data
the Update data in Active Directory
the to Log the changes to the file
The first step is to put the employeeID, which is the personnel number, all users. If users little, to make it easier through ADSI Edit if they are a little more, it is possible to tie the script to the prescription, such as here. And if you have many users, the balance of IDs you want to delegate, I want a nice interface and use additional baubles, you can create an additional tab in the ADUC:

however, the creation of such tabs is in itself a topic for another topic.
The second weak point is that sometimes, for some people, the change should be only some attributes. There is, for example, we have an employee, let's call it Kudryavcev Sadruddin Fatkhullaevich, but he is referred to simply as San Sanych. And there is the CEO, the position of which in the frame is recorded not only as the General Director of Open Joint stock company long-distance Space Communication "Horns And Hoofs", which AD would be better just to leave exactly with the link, but just without the horns and hooves. Thus, we see the need to lay in the logic of our application to certain exceptions and store the exceptions we'll be there in Active Directory in the attribute flags. This attribute has a value of four bytes, and therefore, setting a particular bit in a particular value, we will be able when you need to remember as much as 32 exceptions. However, to use we will still only six.
Turn to the implementation in powershell:
the
Create a test environment, completely arbitrarily assign the names of the accounts:

Now run the script with parameters. Of course, it can schedulet and run according to schedule, not to forget the account on whose behalf the job is executed, to assign the right logon as a batch job:

As you can see, after running, we got a nice readable names, great post and great company names:

Of course, by superficial modifications of the script, we can fill the user everything from phone numbers and addresses to the notorious favorite drinks would be the source. But if the script is run with some regularity, we are seeking to ensure that all user information will be relevant.
upd Corrected a small mistake, moved the reset check boxes inside the loop
Article based on information from habrahabr.ru
First, we describe requirements that we must submit to the accounts of employees. And these requirements we will try to estimate, based on the needs of the user. It is no secret that many enterprise systems using authentication via Active Directory to display in their adminco, and just in the course of work often use a variety of field AD account: Sharepoint, Citrix, and many others. As example I'll take is known to all, MS Outlook, but not completely, but only its address book, which draws its data directly from Active Directory.

Using what user? We have in the organization, he often looks for named phone, email address and the name of the unit. Of course, good fill out and the address information, but due to the fact that the topic we have about conjunction with an abstract of the personnel system, we addresses and phone numbers leave out.
First, we give the list of fields that we wish to take from the personnel system, we will:
the
-
the
- full Name the
- Position the
- Organization the
- Department the
- Postal code the
- Type of employment
Movement
Naturally, in order to associate a person from the HR system and the person from Active Directory, you must have an identifier to link these two records. Usually this ID is the personnel number of the employee, it is assigned to when applying for a job and never changes, however, I have met with situations where the employee ID is not static, in this case the identifier should be invented.
User information Active Directory is not limited to information that can be seen in Active Directory Users and Computers (ADUC established reduction), and very far from being exhausted. In fact, the user object has a trillion attributes, and these attributes can even be added by the administrator of the scheme. For example, there is such attribute as carLicense containing information about driving license, or drink characterizing favorite beverage of the user. In General, Microsoft has provided a lot.
To use my example, I will attributes employeeID to store the user ID, and flags, for what it is, I tell you later.
Also to populate the fields user, we will use the attributes:
the
-
the
- displayName and CN for storing name the
- department storage units the
- company for storage organization the
- title storage office the
- employeeType to store the employee type the
- postalCode storage index,
So, our app will work this way:
the
the deal
The first step is to put the employeeID, which is the personnel number, all users. If users little, to make it easier through ADSI Edit if they are a little more, it is possible to tie the script to the prescription, such as here. And if you have many users, the balance of IDs you want to delegate, I want a nice interface and use additional baubles, you can create an additional tab in the ADUC:

however, the creation of such tabs is in itself a topic for another topic.
The second weak point is that sometimes, for some people, the change should be only some attributes. There is, for example, we have an employee, let's call it Kudryavcev Sadruddin Fatkhullaevich, but he is referred to simply as San Sanych. And there is the CEO, the position of which in the frame is recorded not only as the General Director of Open Joint stock company long-distance Space Communication "Horns And Hoofs", which AD would be better just to leave exactly with the link, but just without the horns and hooves. Thus, we see the need to lay in the logic of our application to certain exceptions and store the exceptions we'll be there in Active Directory in the attribute flags. This attribute has a value of four bytes, and therefore, setting a particular bit in a particular value, we will be able when you need to remember as much as 32 exceptions. However, to use we will still only six.
Turn to the implementation in powershell:
the
# Example of changing user accounts in Active Directory
# Yegor Ivanov
param($strServer, $strContainer, $strUserName, $strPassword, $strFileName, $strLogName)
function Write-LogFile([string]$logFileName)
{
Process
{
$_
$dt = Get-Date
$str = $dt.DateTime + "" + $_
$str | Out-File -FilePath $logFileName -Append
}
}
# This function is actually a stub, its implementation depends
# from a personnel system. There may be a connection to 1C
# and the query in the web, I personally, then picking your Oracle e-Buisness suite
# but for demonstration we will limit ourselves to reading from a csv file.
# It is clear that each time to call Import-CSV stupid
# but like I said, the function stub, it only shows the option
function Get-Employee($employeeID, $fileName, [ref]$title, [ref]$department, [ref]$displayName, [ref]$company, [ref]$postalCode, [ref]$employeeType)
{
$records = $fileName | Import-CSV -Delimiter ";"
$employee = $records | where-object {$_.EmployeeID -eq $employeeID}
if ($employee -eq $null) {return $false}
$title.Value = [string]$employee.Title
$department.Value = [string]$employee.Department
$displayName.Value = [string]$employee.Name
$company.Value = [string]$employee.Company
$postalCode.Value = [string]$employee.PostalCode
$employeeType.Value = [string]$employee.EmployeeType
return $true
}
# Will write to the log
"---" | Write-LogFile $strLogName
"Run with parameters:" | Write-LogFile $strLogName
"Server:" + $strServer | Write-LogFile $strLogName
"Container:" + $strContainer | Write-LogFile $strLogName
"User name:" + $strUserName | Write-LogFile $strLogName
"Password:" + $strPassword | Write-LogFile $strLogName
"File name:" +$strFileName | Write-LogFile $strLogName
"Log file name:" + $strLogName | Write-LogFile $strLogName
# These are our constants, which translate certain attributes in read-only mode
# It is easy to see that they have the value 000001, 000010, 000100, 001000, 010000 and 100000
# in the binary system. This means that their combination unambiguously determine
# which fields to prevent change
New-Variable -Option constant -Name C_COMPANY_FLAG -Value 1
New-Variable -Option constant -Name C_POSTALCODE_FLAG -Value 2
New-Variable -Option constant -Name C_TITLE_FLAG -Value 4
New-Variable -Option constant -Name C_DEPARTMENT_FLAG -Value 8
New-Variable -Option constant -Name C_NAME_FLAG -Value 16
New-Variable -Option constant -Name C_EMPLOYEETYPE_FLAG -Value 32
# Below is the stub for the title attribute. The title attribute for example
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms680037(v=VS.85).aspx
# 64-character maximum size in Windows Server 2003
# or 128 characters maximum size in Windows Server 2008
# so if you do not trim the value that happens the embarrassment
New-Variable -Option constant -Name C_PARAMETERS_LENGTH -Value 64
# (!userAccountControl:1.2.840.113556.1.4.803:=2) read "and account is not locked"
$strFilter = "(&(objectClass=user)(!objectClass=computer)(employeeID=*)(!userAccountControl:1.2.840.113556.1.4.803:=2))"
# Of course, you can use a sample for Active Directory under Windows Server 2008
# http://blogs.msdn.com/adpowershell
# But I decided to make the application compatible with Windows Server 2003 and Windows XP
# so do a dry datecom
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://"+$strServer+"/"+$strContainer)
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"
$colProplist = "employeeID","postalCode","title","department", "displayName", "cn", "employeeType"
foreach ($i in $colPropList)
{
$objSearcher.PropertiesToLoad.Add($i)
}
$colResults = $objSearcher.FindAll()
# Now in colResults we have all the necessary accounts
$startTime = Get-Date
$totalCount = $colResults.Count
$i = 0
foreach ($objResult in $colResults)
{
$objItem = $objResult.Properties
$aDEmployeeID = $objItem.employeeid
# Here is clear, we look at the flags attribute, if we have a ban on changing
# fields, we remember it for the future, lifting any of the boxes
$flagProtectCompany = $false
$flagProtectPostalCode = $false
$flagProtectTitle = $false
$flagProtectDepartment = $false
$flagProtectName = $false
$flagProtectEmployeeType = $false
if (!($objItem.flags -eq $null))
{
$flags = $objItem.flags
if (($flags[0] -band $C_COMPANY_FLAG) -ne 0) {$flagProtectCompany = $true}
if (($flags[0] -band $C_POSTALCODE_FLAG) -ne 0) {$flagProtectPostalCode = $true}
if (($flags[0] -band $C_TITLE_FLAG) -ne 0) {$flagProtectTitle = $true}
if (($flags[0] -band $C_DEPARTMENT_FLAG) -ne 0) {$flagProtectDepartment = $true}
if (($flags[0] -band $C_NAME_FLAG) -ne 0) {$flagProtectName = $true}
if (($flags[0] -band $C_EMPLOYEETYPE_FLAG) -ne 0) {$flagProtectEmployeeType = $true}
}
# This is optional, but I prefer to reset
$CSV = ""
$cSVTitle = ""
$cSVDepartment = ""
$cSVCompany = ""
$cSVPostalCode = ""
$cSVEmployeeType = ""
# Here we should pay attention to the function call in PowerShell, it's not really
# same as in usual languages
$rc = Get-Employee $aDEmployeeID $strFileName ([ref]$cSVTitle) ([ref]$cSVDepartment) ([ref]$CSV) ([ref]$cSVCompany) ([ref]$cSVPostalCode) ([ref]$cSVEmployeeType)
if ($rc)
{
# Here we connect with the directory service under a different name and password than was
# the script is run. It is not wise to implement changes on behalf of the registrant
# it is wiser to delegate changes to someone, and this attribute of the service uchetku
# restricted
$objDirectoryEntry = new-object System.DirectoryServices.DirectoryEntry($objItem.adspath, $strUsername, $strPassword, [System.DirectoryServices.AuthenticationTypes]::Secure)
$oTitle = $cSVTitle
if ($oTitle.Length-gt $C_PARAMETERS_LENGTH) {$oTitle = $oTitle.Substring(0,$C_PARAMETERS_LENGTH)}
$oDepartment = $cSVDepartment
if ($oDepartment.Length-gt $C_PARAMETERS_LENGTH) {$oDepartment = $oDepartment.Substring(0,$C_PARAMETERS_LENGTH)}
$newEmployeeType = $cSVEmployeeType
# Here and below, we check whether the value we want to assign the value
# which already has (and don't forget about the box). This is so as not to strain the directory service
if (($newEmployeeType -ne $objItem.employeetype) -and-not $flagProtectEmployeeType)
{
"Change EmployeeType user """ + $objDirectoryEntry.name + """" | Write-LogFile $strLogName
"""" +$objDirectoryEntry.employeetype + """""" + $newEmployeeType + """" | Write-LogFile $strLogName
$objDirectoryEntry.employeetype = [string]$newEmployeeType
$objDirectoryEntry.CommitChanges()
}
if (($cSVCompany -ne $objItem.company) -and-not $flagProtectCompany)
{
"Change of organization """ + $objDirectoryEntry.name + """" | Write-LogFile $strLogName
"""" +$objDirectoryEntry.company + """""" + $cSVCompany + """" | Write-LogFile $strLogName
$objDirectoryEntry.company = [string]$cSVCompany
$objDirectoryEntry.CommitChanges()
}
if (($cSVPostalCode -ne $objItem.postalcode) -and-not $flagProtectPostalCode)
{
"The change in the index of the user """ + $objDirectoryEntry.name + """" | Write-LogFile $strLogName
"""" +$objDirectoryEntry.postalCode + """""" + $cSVPostalCode + """" | Write-LogFile $strLogName
$objDirectoryEntry.postalCode = $cSVPostalCode
$objDirectoryEntry.CommitChanges()
}
if (($oTitle -ne $objItem.title) -and-not $flagProtectTitle)
{
"Changing the position of the user """ + $objDirectoryEntry.name + """" | Write-LogFile $strLogName
"""" +$objDirectoryEntry.title + """""" + $cSVTitle + """" | Write-LogFile $strLogName
if ($title.Length-gt $C_PARAMETERS_LENGTH)
{
$objDirectoryEntry.title = $cSVTitle.Substring(0,$C_PARAMETERS_LENGTH)
}
else
{
$objDirectoryEntry.title = $cSVTitle.ToString()
}
$objDirectoryEntry.CommitChanges()
}
if (($oDepartment -ne $objItem.department) -and-not $flagProtectDepartment)
{
"Changing the units "user"" + $objDirectoryEntry.name + """" | Write-LogFile $strLogName
if ($department.Length-gt $C_PARAMETERS_LENGTH)
{
$objDirectoryEntry.department = $cSVDepartment.Substring(0,$C_PARAMETERS_LENGTH)
}
else
{
$objDirectoryEntry.department = $cSVDepartment.ToString()
}
$objDirectoryEntry.description = $cSVDepartment.ToString()
$objDirectoryEntry.CommitChanges()
}
if ((($CSV -ne $objItem.displayname) -or ($CSV -ne $objItem.cn)) -and-not $flagProtectName)
{
"Change user name """ + $objDirectoryEntry.name + """" | Write-LogFile $strLogName
"""" +$objDirectoryEntry.displayname + """""" + $CSV + """" | Write-LogFile $strLogName
$objDirectoryEntry.displayName = $CSV
$objDirectoryEntry.CommitChanges()
$objDirectoryEntry.Rename("cn="+$CSV)
}
$i++
# Here we will create the status line, and we will demonstrate simple mathematical operations
# show us, when, finally, the process of the combing of billions of our users will stop
$status = $i.ToString() + " of " + $totalCount.ToString() + "complete -" + $objDirectoryEntry.name
$currentTime = Get-Date
$diffTime = [int][System.Math]::Round(($currentTime - $startTime).Ticks / $i)
$delta = $diffTime*$totalCount
$endTime = $startTime.Add([int64]($delta))
$activityString = "Enumeration of users. The estimated completion time " + $endTime
Write-Progress -Activity $activityString -Status $status -PercentComplete (($i / $totalCount) * 100)
}
}
"Work finished" | Write-LogFile $strLogName
# And don't forget to squeak from the speaker, you never know
Write-Host `a
Create a test environment, completely arbitrarily assign the names of the accounts:

Now run the script with parameters. Of course, it can schedulet and run according to schedule, not to forget the account on whose behalf the job is executed, to assign the right logon as a batch job:

As you can see, after running, we got a nice readable names, great post and great company names:

Of course, by superficial modifications of the script, we can fill the user everything from phone numbers and addresses to the notorious favorite drinks would be the source. But if the script is run with some regularity, we are seeking to ensure that all user information will be relevant.
upd Corrected a small mistake, moved the reset check boxes inside the loop
Комментарии
Отправить комментарий