Script repository
The script compares values of user properties with data contained in a CSV file. Discrepancies are sent via email. To execute the script, create a scheduled task configured for the Domain object type and add a managed domain to the Activity Scope of the task. The domain will only be used to trigger execution of the scheduled task.
Parameters
$csvFilePath- a path to the CSV file to compare AD data to.$identityColumnName- the header of the column that contains user identities. User accounts will be matched by the value of this column.$identityPropertyName- the name of the property that contains the user identity. Users will be matched by the value of this property.$propertiesToCheck- maps CSV column headers with names of the corresponding properties. Only properties included in this map will be compared.$to- the address of the email notification recipient.$subject- the email notification subject.$reportHeader- the report header.$reportFooter- the report footer.
$csvFilePath = "\ServerShareUsers.csv" # TODO: modify me
$identityColumnName = "sAMAccountName" # TODO: modify me
$identityPropertyName = "sAMAccountName" # TODO: modify me
$propertiesToCheck = @{
"EmployeeType" = "employeeType"
"Title" = "title"
"EmployeeID" = "employeeID"
"Manager" = "manager"
"DepartmentNumber" = "departmentNumber"
} # TODO: modify me. Example: $propertiesToCheck = @{"<column name>" = "<property LDAP name>"}
# Email settings
$to = "recipient@example.com" # TODO: modify me
$subject = "Discrepancies between Active Directory and CSV Data" # TODO: modify me
$reportHeader = "<h2><b>Discrepancies between Active Directory and CSV Data</b></h2>" # TODO: modify me
$reportFooter = "<hr /><p><i>Please do not reply to this e-mail, it has been sent to you for notification purposes only.</i></p>" # TODO: modify me
# Import CSV
if (-not (Test-Path -Path $csvFilePath))
{
$Context.LogMessage("File '$csvFilePath' not found", "Warning")
return
}
$importedUsers = Import-Csv -Path $csvFilePath | Where {(-not([System.String]::IsNullOrEmpty($_.$identityColumnName)))}
# Specify settings for user search.
$searcher = $Context.TargetObject
$searcher.PageSize = 500
$propertiesToLoad = @($propertiesToCheck.Values)
$propertiesToLoad += $identityPropertyName
$searcher.SetPropertiesToLoad($propertiesToLoad)
$searcher.ReferralChasing = "ADS_CHASE_REFERRALS_NEVER"
$searcher.VirtualRoot = $True
$usersInCSV = @{}
for ($i = 0; $i -lt $importedUsers.Length; $i++)
{
if ($NULL -eq $criteria)
{
$criteria = New-AdmCriteria -Type "User"
$criteria["User"].SetLogicalOperator("OR")
}
# Get user identity.
$userFromCSV = $importedUsers[$i]
$identity = $userFromCSV.$identityColumnName
if ($usersInCSV.ContainsKey($identity))
{
$usersInCSV[$identity] = $NULL
continue
}
else
{
$usersInCSV.Add($identity, @{
"UserDataFromCSV" = $userFromCSV
"UserDataFromAD" = $NULL
})
}
# Build search filter.
$criteria["User"].Add({$identityPropertyName -eq $identity})
$remainder = 0
[void][System.Math]::DivRem($i, 500, [ref]$remainder)
if ((($i -ne 0) -and ($remainder -eq 0)) -or ($i -eq $importedUsers.Length - 1))
{
# Search users
$searcher.Criteria = $criteria
try
{
$searchResultIterator = $searcher.ExecuteSearch()
$searchResults = $searchResultIterator.FetchAll()
foreach ($searchResult in $searchResults)
{
$userIdentity = $searchResult.Properties[$identityPropertyName].Value
$userInfo = $usersInCSV[$userIdentity]
if ($userInfo -eq $NULL)
{
continue
}
elseif ($userInfo.UserDataFromAD -ne $NULL)
{
$usersInCSV[$userIdentity] = $NULL
continue
}
$userInfo.UserDataFromAD = $searchResult
}
}
finally
{
# Release resources
if ($searchResultIterator) { $searchResultIterator.Dispose() }
}
# Clear criteria
$criteria = $NULL
}
}
# Update user information.
$reports = @{
"NotFound" = New-Object "System.Text.StringBuilder"
"FoundMoreThanOne" = New-Object "System.Text.StringBuilder"
"ValuesDontMatch" = New-Object "System.Text.StringBuilder"
}
foreach ($item in $usersInCSV.GetEnumerator())
{
if ($item.Value -eq $NULL)
{
[void]$reports["FoundMoreThanOne"].Append("<li>")
[void]$reports["FoundMoreThanOne"].Append($item.Key)
[void]$reports["FoundMoreThanOne"].Append("</li>")
continue
}
elseif ($item.Value.UserDataFromAD -eq $NULL)
{
[void]$reports["NotFound"].Append("<li>")
[void]$reports["NotFound"].Append($item.Key)
[void]$reports["NotFound"].Append("</li>")
continue
}
# Compare properties
$userDataFromCSV = $item.Value.UserDataFromCSV
$userDataFromAD = $item.Value.UserDataFromAD
$userRecord = $NULL
foreach($columnName in $propertiesToCheck.Keys)
{
$valueInCSV = $userDataFromCSV.$columnName
$propertyName = $propertiesToCheck[$columnName]
$valueInAD = $userDataFromAD.Properties[$propertyName].Value
if ($valueInAD -eq $NULL)
{
$valueInAD = [System.String]::Empty
}
if ($valueInCSV -eq $valueInAD)
{
continue
}
if ($userRecord -eq $NULL)
{
$userRecord = New-Object "System.Text.StringBuilder"
$userName = $Context.GetDisplayNameFromAdsPath($userDataFromAD.AdsPath)
[void]$userRecord.Append("<li>$userName<table border='1' width='100%%'><tr><th width='30%%'>Property name</th><th width='30%%'>Value in CSV</th><th width='30%%'>Value in AD</th></tr>")
}
[void]$userRecord.Append("<tr><td>$propertyName</td><td>$valueInCSV</td><td>$valueInAD</td></tr>")
}
if ($userRecord -ne $NULL)
{
[void]$userRecord.Append("</table><br/>")
[void]$userRecord.Append("</li>")
[void]$reports["ValuesDontMatch"].Append($userRecord.ToString())
}
}
# Build report
$report = New-Object "System.Text.StringBuilder"
if ($reports["FoundMoreThanOne"].Length -eq 0 -and
$reports["NotFound"].Length -eq 0 -and
$reports["ValuesDontMatch"].Length -eq 0)
{
[void]$report.Append("<b>Found no discrepancies between the CSV file and Active Directory</b>")
}
else
{
if ($reports["NotFound"].Length -ne 0)
{
[void]$report.Append("<h3>The following users were not found in Active Directory: </h3><ul>")
[void]$report.Append($reports["NotFound"].ToString())
[void]$report.Append("</ul>")
}
if ($reports["FoundMoreThanOne"].Length -ne 0)
{
[void]$report.Append("<h3>Each of the following names were found in more than one user account: </h3><ul>")
[void]$report.Append($reports["FoundMoreThanOne"].ToString())
[void]$report.Append("</ul>")
}
if ($reports["ValuesDontMatch"].Length -ne 0)
{
[void]$report.Append("<h3>The following properties of the following users did not match:</h3><ul>")
[void]$report.Append($reports["ValuesDontMatch"].ToString())
[void]$report.Append("</ul>")
}
}
# Build report
$html = "$reportHeader$($report.ToString())$reportFooter"
# Send mail
$Context.SendMail($to, $subject, $NULL, $html)
Comments 3
You must be signed in to comment.
Pudong
Hello
In my CSV file the manager value is saved as samAccountName and not as Object DN?
For example
Value in CSV: jdoe
Value in AD: CN=Jon Doe,OU=user,DC=domain,DC=gvb,DC=local
Do you have a suggestion on how the script can be modified so that these values can also be compared?
regards
pudong
Support
Hello,
Unfortunately, there is no easy way to do that. The thing is that manager is a DN-syntax property which means it stores a distinguished name of an object.
Pudong
Hello,
I found the necessary hint on how to parse the value in this import script:
https://www.adaxes.com/script-repository/import-new-and-updated-users-from-csv-file-s246.htm
I have now updated my script, and it's working as desired. Here my code: