Hello,
Find the updated script below:
$waitTimeSeconds = 9 * 60 # TODO: modify me. Time in seconds
$scriptBLock = {
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")
$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")
$csvFilePath = "\\Server\Share\Users.csv" # TODO: modify me
$identityColumnName = "sAMAccountName" # TODO: modify me
$identityPropertyLdapName = "sAMAccountName" # TODO: modify me
$customColumnNames = @{
"AccountPassword" = "unicodePwd"
} # TODO: modify me
$skipColumns = @() # TODO: modify me
# E-mail settings
$recipient = "recipient@domain.com" # TODO: Modify me
$from = "noreply@domain.com" # TODO: Modify me
$subject = "Error Report: Import data from csv" # TODO: Modify me
$smtpServer = "mail.domain.com" # TODO: Modify me
$reportHeader = "<h1><b>Error Report: Import data from csv</b></h1><br/>"# 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
function SendMail ($html)
{
Send-MailMessage -to $recipient -From $from -Subject $subject -Body $html -SmtpServer $smtpServer -BodyAsHtml
}
# Import CSV
$report = New-Object "System.Text.StringBuilder"
try
{
[System.Array]$importedUsers = Import-Csv -Path $csvFilePath -ErrorAction Stop | Where {(-not([System.String]::IsNullOrEmpty($_.$identityColumnName)))}
}
catch
{
$message = "An error occurred while importing CSV file '$csvFilePath'. Error: " + $_.Exception.Message
Write-Warning $message
$html = $reportHeader + "<h3>$message</h3>" + $reportFooter
SendMail $html
return
}
# Create user searcher
$searcher = $admService.OpenObject("Adaxes://%distinguishedName%", $NULL, $NULL, 0)
$searcher.PageSize = 500
$searcher.SetPropertiesToLoad(@($identityPropertyLdapName))
# Create properties mapping
$propertyMap = @{}
foreach ($property in $importedUsers[0].PsObject.Properties)
{
if (($property.Name -eq $identityColumnName) -or ($skipColumns -contains $property.Name))
{
continue
}
if ($customColumnNames.ContainsKey($property.Name))
{
$propertyMap.Add($customColumnNames[$property.Name], $property.Name)
}
else
{
$propertyMap.Add($property.Name, $property.Name)
}
}
$propertiesForUpdate = @($propertyMap.Keys)
$filter = New-Object "System.Text.StringBuilder"
$usersFromCSV = @{}
for ($i = 0; $i -lt $importedUsers.Length; $i++)
{
# Get user identity
$userFromCSV = $importedUsers[$i]
$identity = $userFromCSV.$identityColumnName
if ($usersFromCSV.ContainsKey($identity))
{
$usersFromCSV[$identity] = $NULL
continue
}
else
{
$usersFromCSV.Add($identity, @{
"Path" = $NULL
"UserData" = $userFromCSV
})
}
# Build filter
[void]$filter.Append([Softerra.Adaxes.Ldap.FilterBuilder]::Create($identityPropertyLdapName, $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.SearchFilter = "(&(sAMAccountType=805306368)(|" + $filter.ToString() + "))"
try
{
$searchResultIterator = $searcher.ExecuteSearch()
$searchResults = $searchResultIterator.FetchAll()
foreach ($searchResult in $searchResults)
{
$name = $searchResult.Properties[$identityPropertyLdapName].Value
$userInfo = $usersFromCSV[$name]
if ($userInfo -eq $NULL)
{
continue
}
elseif ($userInfo.Path -ne $NULL)
{
$usersFromCSV[$name] = $NULL
continue
}
$userInfo.Path = $searchResult.AdsPath
}
}
finally
{
# Release resources
if ($searchResultIterator) { $searchResultIterator.Dispose() }
}
# Clear filter
$filter.Length = 0
$filter.Capacity = 0
}
}
# Update users
$errorReport = @{
"NotFound" = New-Object "System.Text.StringBuilder"
"FoundMoreThanOne" = New-Object "System.Text.StringBuilder"
"UpdateOperationErrors" = New-Object "System.Text.StringBuilder"
}
foreach ($item in $usersFromCSV.GetEnumerator())
{
if ($item.Value -eq $NULL)
{
# Add user to report
[void]$errorReport["FoundMoreThanOne"].Append("<li>" + $item.Key + "</li>")
continue
}
elseif ($item.Value.Path -eq $NULL)
{
# Add user to report
[void]$errorReport["NotFound"].Append("<li>" + $item.Key + "</li>")
continue
}
# Bind to a user
$user = $admService.OpenObject($item.Value.Path, $NULL, $NULL, 0)
# Set properties
foreach ($ldapPropertyName in $propertyMap.Keys)
{
$columnName = $propertyMap[$ldapPropertyName]
if ($ldapPropertyName -eq "description")
{
# Check existing value of description
try
{
$value = $user.Get("description")
}
catch
{
$value = ""
}
if ($value.StartsWith("ADM", "CurrentCultureIgnoreCase"))
{
continue
}
}
$user.Put($ldapPropertyName, $item.Value.UserData.$columnName)
}
try
{
# Commit changes
$user.SetInfoEx($propertiesForUpdate)
}
catch
{
$errorMessage = "<li>$($item.Key) - $($_.Exception.Message)</li>"
[void]$errorReport["UpdateOperationErrors"].Append($errorMessage)
}
}
if ($errorReport["FoundMoreThanOne"].Length -eq 0 -and
$errorReport["NotFound"].Length -eq 0 -and
$errorReport["UpdateOperationErrors"].Length -eq 0)
{
return # No errors
}
$html = New-Object "System.Text.StringBuilder"
[void]$html.Append($reportHeader)
if ($errorReport["NotFound"].Length -ne 0)
{
[void]$html.Append("Names of users that were not found:<ul>")
[void]$html.Append($errorReport["NotFound"].ToString())
[void]$html.Append("</ul><br/>")
}
if ($errorReport["FoundMoreThanOne"].Length -ne 0)
{
[void]$html.Append("Found more than one user with the following name:<ul>")
[void]$html.Append($errorReport["FoundMoreThanOne"].ToString())
[void]$html.Append("</ul><br/>")
}
if ($errorReport["UpdateOperationErrors"].Length -ne 0)
{
[void]$html.Append("Errors that occured when updating users:<ul>")
[void]$html.Append($errorReport["UpdateOperationErrors"].ToString())
[void]$html.Append("</ul><br/>")
}
[void]$html.Append($reportFooter)
# Send mail
SendMail $html
}
# Start Windows PowerShell as a separate process and run the script block in that process
$job = Start-Job -ScriptBlock $scriptBlock
Wait-Job -Job $job -Timeout $waitTimeSeconds
if ($job.State -ne "Completed")
{
$Context.LogMessage("The operation did not complete within the allowed timeout of $waitTimeSeconds seconds. " +
"It will be moved to a separate instance and completed on the background.", "Warning")
return
}
# Get output from separate process
Receive-Job -Job $job