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.

Script Repository

Import photos for users in Organizational Unit

November 23, 2023 Views: 2122

The script imports photos for users located in a certain Organizational Unit. To update photos on a regular basis, you need to create a scheduled task for the Domain object type that runs the script.

Note: Photos will be imported only if a user does not have a photo assigned in AD.

Parameters:

  • $extensions - Specifies the extensions of the pictures to import.
  • $ouDNs - Maps distinguished names (DNs) of the Organizational Units where users for which to import photos 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 - Specifies the LDAP name of the property whose value will be used to form file names for user pictures.
  • $pictureAttribute - Specifies the LDAP name of the property where user pictures will be imported.
  • $to - Specifies the address of the email notification recipient.
  • $subject - Specifies the email notification subject.
  • $reportHeader - Specifies the report header.
  • $reportFooter - Specifies the report footer.
See Also: Import user photo.
Edit Remove
PowerShell
$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)
{
    # Find users
    $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
    {
        $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 12
avatar
Tim May 22, 2020
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."
avatar
Support May 22, 2020

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?

avatar
Mike Aug 20, 2020
Can this be modified to search multiple OUs?
avatar
Support Aug 21, 2020

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.

avatar
mike Aug 21, 2020
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!
avatar
Support Aug 25, 2020

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.

avatar
Mike Aug 26, 2020
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!
avatar
Support Aug 27, 2020

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

avatar
Mike Aug 27, 2020
Yeah that would be enough for me. We use cn instead of employee id, but that's easy enough to replace.
avatar
Support Aug 28, 2020

Hello Mike,

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

avatar
Mike Aug 28, 2020
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?
avatar
Support Aug 28, 2020

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.

avatar
Mike Aug 28, 2020
Excellent! Works perfectly now. I did add the following line to use the photo optimization script. $user = $Context.BindToObjectEx($searchResult.AdsPath, $True)
Leave a comment
Loading...

Got questions?

Support Questions & Answers