0 votes

We are trying to mass change user photos through a scripted method. We are using a modified version of the Import User Photo and Optimize User Photo scripts. Optimization script is posted below the post.

The import script is configured as a custom command.
The optimize script as a business rule to run before updating a user if the jpegPhoto attribute has changed.

When I edit the jpegPhoto manually the business rule and script perform as expected.

  • Get the modified bytes of jpegPhoto.

  • Check dimensions and byte count.

    • Scale and reduce quality if needed.
  • Create thumbnailPhoto

    • Reduce quality if needed.
  • Set jpegPhoto and thumbnailPhoto

When I run the Import user photo script targeted at a user, the imported photo is not scaled and quality is not reduced.
However, the thumbnail is created and saved.

Any ideas?

## Contants
$maxThumbnailDimension = 300
$maxThumbnailKB = 100
$maxJpegDimension = 1200
$maxJpegKB = 600

## Functions
function DeleteTmpFile ($filePath)
{
    [System.IO.File]::Delete($filePath)
}

function CheckFileSizeAndSave ($filePath, $quality, $imageFormat, $imageCodecInfo, $maxBytes, $picture)
{
    if ($quality -lt 0)
    {
        DeleteTmpFile $filePath
        return
    }

    # Set encoder settings for image quality 
    $encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
    $encoder = [System.Drawing.Imaging.Encoder]::Quality
    $encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($encoder, $quality)

    # Save file
    $picture.Save($filePath, $imageCodecInfo, $($encoderParams))

    # Check file size
    $fileSize = (Get-Item $filePath).Length / 1kb
    if ($fileSize -lt $maxBytes)
    {
        return
    }
    else
    {
        $quality = $quality - 5
        CheckFileSizeAndSave $filePath $quality $imageFormat $imageCodecInfo $maxBytes $picture
    }
}

function UpdateUserPhotos ($jpegPhotoPath, $thumbnailPhotoPath)
{
    if (!(Test-Path $thumbnailPhotoPath))
    {
        $Context.Cancel("Automatic thumbnail creation failed.")
        return
    }

    # Update the thumbnailPhoto attribute
    $jpegPhotoBytes = [System.IO.File]::ReadAllBytes($jpegPhotoPath)
    $Context.SetModifiedPropertyValue("jpegPhoto", $jpegPhotoBytes)

    $gamOutput = & "c:\gam\gam.exe" user '%mail%' update photo $jpegPhotoPath 2>&1
    if ($gamOutput -like "*Error*"){
        Write-Error "$gamOutput"
    }else{
        $Context.LogMessage("%mail% profile photo has been updated.", "Information")
    }

    # Update the thumbnailPhoto attribute
    $thumbnailPhotoBytes = [System.IO.File]::ReadAllBytes($thumbnailPhotoPath)
    $Context.SetModifiedPropertyValue("thumbnailPhoto", $thumbnailPhotoBytes)

    # Delete the temporary file
    DeleteTmpFile $thumbnailPhotoPath
    DeleteTmpFile $jpegPhotoPath
}

$jpegPhotoBytes = $Context.GetModifiedPropertyValue("jpegPhoto")
if ([System.String]::IsNullOrEmpty($jpegPhotoBytes))
{
    return # The jpegPhoto attribute is empty
}

try
{
    $original = [System.Drawing.Image]$jpegPhotoBytes
    $originalWidth = $original.Width
    $originalHeight = $original.Height
    $originalRatio = $originalWidth / $originalHeight

    if ($originalRatio -ne 1) {
        $Context.Cancel("Please upload a square ratio (1:1) photo.")
    }

    if ($originalHeight -lt $maxJpegDimension) {
        $Context.Cancel("Please upload a photo that is at least $maxJpegDimension x $maxJpegDimension.")
    }

    $jpegPhotoFilePath = [System.IO.Path]::GetTempFileName()
    $thumbnailPhotoFilePath = [System.IO.Path]::GetTempFileName()
    $imageFormat = "System.Drawing.Imaging.ImageFormat" -as [type]
    $imageCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | where {$_.MimeType -eq 'image/jpeg'}

    # Check original size
    if ($originalHeight -gt $maxJpegDimension)
    {

        # Resize the picture
        $newJpegPicture = $original.GetThumbnailImage($maxJpegDimension, $maxJpegDimension, $null, [intptr]::Zero)
        CheckFileSizeAndSave $jpegPhotoFilePath 100 $imageFormat $imageCodecInfo $maxJpegKB $newJpegPicture
        if (!(Test-Path $jpegPhotoFilePath))
        {
            $Context.Cancel("Automatically resize jpeg failed.")
            return
        }
    }
    else
    {
        CheckFileSizeAndSave $jpegPhotoFilePath 100 $imageFormat $imageCodecInfo $maxJpegKB $original
    }

    $newThumbnailPicture = $original.GetThumbnailImage($maxThumbnailDimension, $maxThumbnailDimension, $null, [intptr]::Zero)
    CheckFileSizeAndSave $thumbnailPhotoFilePath 100 $imageFormat $imageCodecInfo $maxThumbnailKB $newThumbnailPicture
    if (!(Test-Path $thumbnailPhotoFilePath))
    {
        $Context.Cancel("Automatically resize thumbnail failed.")
        return
    }

    UpdateUserPhotos $jpegPhotoFilePath $thumbnailPhotoFilePath
}
finally
{
    # Release resources
    if ($original) { $original.Dispose() }
    if ($newJpegPicture) { $newJpegPicture.Dispose() }
    if ($newThumbnailPicture) { $newThumbnailPicture.Dispose() }
}
by (1.2k points)

1 Answer

0 votes
by (270k points)
selected by
Best answer

Hello,

The thing is that your Business Rule is configured to trigger only if the jpegPhoto property is updated. If the import script performs the update directly in Active Directory, the Business Rule will not trigger. For the scenario to work properly, you need to pass the jpegPhoto property update through Adaxes pipeline. Find the updated Import User Photo script below.

$picturePath = "\\SERVER\Share\%username%.png"  # TODO: modify me

# Check whether the picture file exists
if(!(Test-Path -Path $picturePath))
{
    $Context.LogMessage("File does not exist '$picturePath'.", "Error")
    return
}

# Update picture
[Byte[]]$pictureBytes = Get-Content $picturePath -Encoding Byte
$user = $Context.BindToObjectEx($Context.TargetObject.AdsPath, $True)
$user.Put("jpegPhoto", $pictureBytes)
$user.SetInfo()
0

Thank you for the fix!

Related questions

0 votes
1 answer

After we updated our site to 2018.1 suddenly the Password Self Service link is throwing an error: " Could not load file or assembly 'Softerra.Adaxes.Adsi, Version= ... . The system cannot find the file specified." Other interfaces are workin as expected.

asked Jul 20, 2018 by johnsonua (390 points)
0 votes
1 answer

We currently have a form for HR to deal with ex-employees that are hired once more, but it's not much more than automatic emails sent to IT. If I add some actions ... this trigger the business rule we have that targets "After updating a user" ? Thanks, Louis

asked Oct 18, 2022 by lw.fa (130 points)
0 votes
1 answer

Hello, I have an LDAP filter on a home page action : (& (objectClass = organizationalUnit) (name = * Users)) But nothing appears When I do the search from the console with my filter, it works: the OU Users * did not directly at the domain root

asked Dec 14, 2011 by mmichard (360 points)
0 votes
1 answer

Hello, I have a problem when I created a new user with a mailbox with the first or last name has an accent. only Internal users of the company have a delivery ... .ADR.ExRecipNotFound; not found ## If I create the same user without accent, everything works.

asked Dec 2, 2011 by mmichard (360 points)
0 votes
1 answer

Hi all I need to modify the template $remoteRoutingAddressTemplate with the default exchange option automatically update email addresses disable. How i make it?

asked Nov 28, 2022 by Simone.Vailati (430 points)
3,326 questions
3,026 answers
7,727 comments
544,678 users