Script repository

Import photos for users in Organizational Unit

Updated on: Jan 18, 2026, Views: 2985

Import data

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

    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

      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

    Mike

    Can this be modified to search multiple OUs?

    • Support

      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

    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

      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

        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

          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

            Mike

            Yeah that would be enough for me. We use cn instead of employee id, but that's easy enough to replace.

            • Support

              Support

              Hello Mike,

              Thank you for the confirmation. We updated the script accordingly.

  • Mike

    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

      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

    Mike

    Excellent! Works perfectly now. I did add the following line to use the photo optimization script.

    $user = $Context.BindToObjectEx($searchResult.AdsPath, $True)
    

Got questions?

Support Questions & Answers

We use cookies to improve your experience.
By your continued use of this site you accept such use.
For more details please see our privacy policy and cookies policy.