Script repository
The script imports photos for users located in a certain Organizational Unit. Also the script emails a report of the import results. 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.
Photos will be imported only for the users that do not have a photo assigned in AD.
Parameters
$extensions- the extensions of the pictures to import.$ouDNs- maps distinguished names (DNs) of the Organizational Units where users to import photos for are located with the paths to shares where pictures are stored. In the paths, the 0 placeholder will be replaced with the value of the $pictureNameAttribute variable.$pictureNameAttribute- the name of the property whose value will be used to form file names of user pictures.$pictureAttribute- the name of the property where user pictures will be imported.$to- the address of the email notification recipient.$subject- the email notification subject.$reportHeader- the report header.$reportFooter- the report footer.
$extensions = @("jpg", "png") # TODO: modify me
$ouDNs = @{
"OU=Users1,DC=domain,DC=com" = "\\server1\share\{0}.{1}"
"OU=Users2,DC=domain,DC=com" = "\\server2\share\{0}.{1}"
} # TODO: modify me
$pictureNameAttribute = "employeeID" # TODO: modify me
$pictureAttribute = "thumbnailPhoto" # TODO: modify me
# Email settings
$to = "recipient@domain.com" # TODO: modify me
$subject = "User photos updated on %datetime%" # TODO: modify me
$reportHeader = "<h3>User photo update report</h3>" # 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
# Get the default web interface address.
$webInterfaceAddress = "%adm-WebInterfaceUrl%"
if ([System.String]::IsNullOrEmpty($webInterfaceAddress))
{
$Context.LogMessage("Default Web Interface address not set for Adaxes service. For details, see http://www.adaxes.com/help/?HowDoI.ManageService.RegisterWebInterface.html", "Warning")
}
$updateUserNames = New-Object System.Text.StringBuilder
$notFoundFiles = New-Object System.Text.StringBuilder
# Build criteria
$criteria = New-AdmCriteria "user"
$simpleItem1 = $criteria.CreateSimple()
$simpleItem1.SetProperty($pictureAttribute).SetComparisonOperator("empty").AddValue($True)
$simpleItem2 = $criteria.CreateSimple()
$simpleItem2.SetProperty($pictureNameAttribute).SetComparisonOperator("empty").AddValue($False)
$criteria["user"].Add($simpleItem1).Add($simpleItem2)
foreach ($dn in $ouDNs.Keys)
{
# Search parameters
$searcher = $Context.BindToObjectByDN($dn)
$searcher.Criteria = $criteria
$searcher.SearchScope = "ADS_SCOPE_SUBTREE"
$searcher.ReferralChasing = "ADS_CHASE_REFERRALS_NEVER"
$searcher.PageSize = 500
$searcher.SetPropertiesToLoad(@($pictureNameAttribute, "objectGUID"))
try
{
# Execute search
$searchResultIterator = $searcher.ExecuteSearch()
$searchResults = $searchResultIterator.FetchAll()
$picturePathTemplate = $ouDNs[$dn]
foreach ($searchResult in $searchResults)
{
# Build photo path.
$fileName = $searchResult.Properties[$pictureNameAttribute].Value
$picturePath = $NULL
foreach ($extension in $extensions)
{
$picturePath = [System.String]::Format($picturePathTemplate, @($fileName, $extension))
if(!(Test-Path -Path $picturePath))
{
$picturePath = $NULL
continue
}
break
}
if ($NULL -eq $picturePath)
{
$notFoundFiles.Append("<li>$fileName</li>")
continue
}
# Update user photo.
$user = $Context.BindToObject($searchResult.AdsPath)
$username = $user.Get("name")
try
{
[Byte[]]$pictureBytes = [System.Io.File]::ReadAllBytes($picturePath)
$user.Put($pictureAttribute, $pictureBytes)
$user.SetInfo()
}
catch
{
$Context.LogMessage("An error occurred while updating picture for user '$username'. Error: " + $_.Exception.Message, "Warning")
continue
}
# Add user to report.
$guid = [Guid]$searchResult.Properties["objectGUID"].Value
$userLink = "<a href='$webInterfaceAddress`#/Browse/$guid'>$username</a>"
$updateUserNames.Append("<li>$userLink</li>")
}
}
finally
{
$searchResultIterator.Dispose()
}
}
# Build html
$html = New-Object System.Text.StringBuilder
$html.Append($reportHeader)
$html.Append("<b>Users with updated photos</b>")
if ($updateUserNames.Length -eq 0)
{
$html.Append("<b>Users are not updated</b>")
}
else
{
$html.Append("<ol>")
$html.Append($updateUserNames.ToString())
$html.Append("</ol>")
}
$html.Append("<br/>")
if ($notFoundFiles.Length -ne 0)
{
$html.Append("<b>No picture for users with the following $pictureNameAttribute were found:</b>")
$html.Append("<ol>")
$html.Append($notFoundFiles.ToString())
$html.Append("</ol>")
}
$html.Append($reportFooter)
# Send mail
$Context.SendMail($to, $subject, $NULL, $html.ToString())
Comments 13
You must be signed in to comment.
Tim
Anyone else able to get this to work? I'm getting an error on line 22. "You cannot call a method on a null-valued expression."
Support
Hello Tim,
As per our check, the script works as intended. For troubleshooting purposes, could you, please, post here or send us (support[at]adaxes.com) the exact script you are using with all the modifications made?
Mike
Can this be modified to search multiple OUs?
Support
Hello Mike,
Yes, it is possible. Should it be a single share containing pictures for users in all the OUs or each OU will have a separate share? Any additional details regarding the required script modifications will be much appreciated.
Mike
The way we have our OUs and photo shares setup is below.
OU Company A.1 to \\server\share \company a
OU Company A.2 to \\server\share \company a
OU Company A.3 to \\server\share \company a
OU Company B to \\server\share \company b
OU Company C to \\server\share \company c
We also have jpg & png files and it would be helpful to scan and import both.
Let me know if you need any details.
Thanks!
Support
Hello Mike,
Thank you for the provided details. We updated the script accordingly. For example, now the $ouDNs variable maps distinguished names of OUs with paths to user pictures.
Mike
This is excellent! Works perfectly!
One last request (I promise): Can the email include any errors from the script? Example: some users' photos are missing from the server share.
Thank you so much!
Support
Hello Mike,
Yes, it is possible. What information do you need to be included? Would something like the below meet your needs?
No picture for users with the following employee IDs were found:
employee ID 1
employee ID 2
employee ID 3
Mike
Yeah that would be enough for me. We use cn instead of employee id, but that's easy enough to replace.
Support
Hello Mike,
Thank you for the confirmation. We updated the script accordingly.
Mike
OK, it works but isn't formatted for easy reading. The text below is in one line without spaces between the account names.
"Users with updated photosUsers are not updatedNo picture for users with the following cn were found:Bob SmithBob SmithBob SmithBob SmithBob SmithBob Smith"
Can we add spaces between cn's or have them on their own line?
Support
Hello Mike,
Sorry for the confusion, the issue occurs because the script is not properly displayed in our comment. Please, use the main script from the article, it contains all the updates you need.
Mike
Excellent! Works perfectly now. I did add the following line to use the photo optimization script.