Upload user photos to Active Directory using PowerShell

If you use Active Directory, you use Exchange, OwnCloud, SharePoint or another system with the ability to display an avatar or photo, then after reading this article you will be able to upload a user's photo in AD for display in Outlook, Lync, on SharePoint portals and other systems .

I found a similar article ( “Adding Photos to Active Directory” ), but a lot of time passed, I decided to revive the topic.

Requirements:
  • Photos of employees preferably in JPG format; file name, preferably standardized;
  • PowerShell and Active Directory for PowerShell module on the computer;
  • The Active Directory schema must be Win 2008 or newer (this does not mean the presence of controllers for Window 2008, it will only run adprep from the Windows 2008 disk to expand the schema);
  • The user must have rights to change the thumbnailphoto, jpegPhoto attributes in Active Directory (by default, the user can change his photo, but you can delegate the right).


Minuses:
  • Additional load on support with requests to replace the photo;
  • The growth of the Active Directory NTDS.DIT ​​database, which can lead to replication problems.


For reference:
Active Directory limit on thumbnailPhoto and jpegPhoto attribute size is 100 kb. User photos in Outlook 2010 will be displayed even if Exchange is not installed, it is enough to have an Active Directory Win 2008 scheme or newer (This does not mean that there are controllers under Window 2008, just run adprep from a Windows 2008 disk to expand the scheme). To display the user's photo, in different systems, different attributes in Active Directory are used. For example, for display in Outlook thumbnailPhoto, and for display in SharePoint jpegPhoto.


The author is not responsible for any possible harm caused by the materials in this article.

The article does not provide the entire script. The taste and color markers are different.
In fact, it’s easier to break Active Directory with my ready-made script, with ill-considered use.



Or to finish snap Active Directory User & computers


There are several options for uploading photos to AD using PowerShell:

Using the Microsoft PowerShell for Active Directory module:

Import-Module ActiveDirectory
$photo = [byte[]](Get-Content C:\Photo\MyPhoto.jpg -Encoding byte)
Set-ADUser <sAMAaccountName> -Replace @{thumbnailPhoto=$photo} 
Set-ADUser <sAMAaccountName> -Replace @{jpegPhoto;=$photo} 

Using the Quest PowerShell for Active Directory snap-in:

Add-PSSnapin Quest.ActiveRoles.ADManagement
$photo = [byte[]](Get-Content C:\Photo\MyPhoto.jpg -Encoding byte)
Set-QADUser <sAMAaccountName> -ObjectAttributes @{thumbnailPhoto=$photo}
Set-QADUser <sAMAaccountName> -ObjectAttributes @{jpegPhoto=$photo}

Using the PowerShell for Exchange snap-in:

Add-PSSnapin Microsoft.Exchange.Management.Powershell.E2010
Import-RecipientDataProperty -Identity <sAMAaccountName> -Picture -FileData ([Byte[]]$(Get-Content -Path "C:\Photo\MyPhoto.jpg" -Encoding Byte -ReadCount 0))

Snap restriction on file size 10 kb. Replaces only thumbnailphoto.

Using the PowerShell for Exchange 2013 snap-in:

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn
$photo = ([Byte[]] $(Get-Content -Path "C:\Photo\MyPhoto.jpg" -Encoding Byte -ReadCount 0))
Set-UserPhoto -Identity <sAMAaccountName> -PictureData $photo -Confirm:$False
Set-UserPhoto -Identity <sAMAaccountName> -Save -Confirm:$False

Check photo via browser (if you have Exchange 2013)
https: //mail.domain.local/ews/Exchange.asmx/s/GetUserPhoto? Email=user@domain.com&size=HR648x648


Using PowerShell and ADSI:

[byte[]]$jpg = Get-Content "C:\Photo\MyPhoto.jpg" -encoding byte
$user = [adsi]"LDAP://cn=user1,cn=users,dc=domain,dc=loc"
$user.Properties["jpegPhoto"].Clear()
$null = $user.Properties["jpegPhoto"].Add($jpg)
$user.Properties["thumbnailPhoto"].Clear()
$null = $user.Properties["thumbnailPhoto"].Add($jpg)
$user.CommitChanges()

All these examples load the user's photo without changing the size and quality of the image.

For myself, I settled on the use with the Microsoft PowerShell for Active Directory module. But at the very first attempt to upload a photo, I received an error about the impossibility of loading a photo from a file of 5 megabytes in size. The first idea was to convert the photos by compressing them to an acceptable size. But the desire to learn PowerShell won.

So we complicate the task of uploading photos. Add a function to change the resolution of the photo.

The function accepts the full path to the file, maximum resolution, compression quality at the input.

An almost ready-made function was found on the Internet and finished for specific tasks.
Function resizephoto(){
Param ( [Parameter(Mandatory=$True)] [ValidateNotNull()] $imageSource,
[Parameter(Mandatory=$true)][ValidateNotNull()] $canvasSize,
[Parameter(Mandatory=$true)][ValidateNotNull()] $quality )
# функция берет файлик и ужимет его# проверкиif (!(Test-Path $imageSource)){throw( "Файл не найден")}
if ($canvasSize -lt 10 -or $canvasSize -gt 1000){throw( " Параметр размер должен быть от 10 до 1000")}
if ($quality -lt 0 -or $quality -gt 100){throw( " Параметр качества должен быть от 0 до 100")}
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$imageBytes = [byte[]](Get-Content $imageSource -Encoding byte)
$ms = New-Object IO.MemoryStream($imageBytes, 0, $imageBytes.Length)
$ms.Write($imageBytes, 0, $imageBytes.Length);
$bmp = [System.Drawing.Image]::FromStream($ms, $true)
# разрешение картинки после конвертации
$canvasWidth = $canvasSize
$canvasHeight = $canvasSize
# Задание качества картинки
$myEncoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($myEncoder, $quality)
#Получаем тип картинки
$myImageCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders()|where {$_.MimeType -eq 'image/jpeg'}
# Высчитывание кратности
$ratioX = $canvasWidth / $bmp.Width;
$ratioY = $canvasHeight / $bmp.Height;
$ratio = $ratioY
if($ratioX -le $ratioY){
    $ratio = $ratioX
}
# Создание пустой картинки
$newWidth = [int] ($bmp.Width*$ratio)
$newHeight = [int] ($bmp.Height*$ratio)
$bmpResized = New-Object System.Drawing.Bitmap($newWidth, $newHeight)
$graph = [System.Drawing.Graphics]::FromImage($bmpResized)
$graph.Clear([System.Drawing.Color]::White)
$graph.DrawImage($bmp,0,0 , $newWidth, $newHeight)
# Создание пустого потока
$ms = New-Object IO.MemoryStream
$bmpResized.Save($ms,$myImageCodecInfo, $($encoderParams))
# уборка
$bmpResized.Dispose()
$bmp.Dispose()
return $ms.ToArray()
}


Paste this function into the script.

An excerpt the main part of the script, register the path to the photo, login, personnel number, name
  $PhotoPath = '\\server\FOTO\' 
  #создаем PSDrive чтобы избежать проблем с обращениям к сетевым дискам при подключённой оснастке PSSQL 
  New-PSDrive -Name Photo -PSProvider FileSystem -Root $PhotoPath
    $UserLogin = 'login'
    $EmployeeID = '503'
    $FullName = 'Full User Name'# закомментировать для уменьшения вывода
    write-host "Обрабатываем: `n Логин: " $UserLogin "`n номер:"   $EmployeeID "`n ФИО: "  $FullName 
    # проверяем  соответствие логина в AD и внешней системе   
    $aduser = get-aduser $UserLogin -ErrorAction SilentlyContinue 
    if ($aduser.name -ne $FullName) {
            # если не совпадает выводим на экран и ничего не делаем 
            write-host "in Office " $FullName "`n in ad  " $aduser.name  "`nLogin " $UserLogin " `n`n" -ForegroundColor Red
    } else {
        # присваиваем EmployeeID в AD из внешней системы
        Set-ADUser $UserLogin -EmployeeID $EmployeeID
        $PhotoFile = 'Photo:\'+$EmployeeID+'.jpg'
        # проверяем что фото есть
        If (Test-Path $PhotoFile )  {
            # Если есть фото сотрудника
            # указываем путь к фото и качество
            $thumbnailPhoto = [byte[]]( $(resizephoto $PhotoFile 64 80))
            $jpegPhoto = [byte[]]( $(resizephoto $PhotoFile 648 80))
            # добавляем фото в thumbnailPhoto
            Set-ADUser $UserLogin -Replace @{thumbnailPhoto=$thumbnailPhoto} -ErrorVariable ErrorthumbnailPhoto  #-WhatIf
            if ($ErrorthumbnailPhoto -ne $null) {
                # в случае ошибки
                write-host "Ошибка добавления thumbnailPhoto на логине "$UserLogin  " ID " $_.autokey
                exit
			} 
            # добавляем фото в jpegPhoto
            Set-ADUser $UserLogin -Replace @{jpegPhoto=($jpegPhoto)} -ErrorVariable ErrorjpegPhoto #-WhatIf
            if ($ErrorjpegPhoto -ne $null) {
                # в случае ошибки
                write-host "Ошибка добавления jpegPhoto на логине "$UserLogin  " ID " $_.autokey
                exit
			} 
            if (!$ErrorthumbnailPhoto -and !$ErrorjpegPhoto) {
                # Если без ошибок
                # закомментировать для уменьшения вывода
                write-host 'Обработали...' -ForegroundColor Green
            }
        } else {
            # Если нет фото
            Write-Host " Фото " $PhotoFile " для " $UserLogin " не найдено"  -foregroundcolor red
        }
    }


The path to the photo was set via PSDrive, because after connecting the PowerShell PSSQL module to work with MS SQL, the current path changes to PS SQLSERVER: \> and accessing network resources without changing the folder becomes impossible. The photo is stored on a network resource, where the file name is personnel number. The example removes logging and error handling.


Uploading photos from Active Directory:
Some examples for checking the correctness of uploading photos to Active Directory.

Using the Microsoft PowerShell for Active Directory module:

Import-Module ActiveDirectory
$user = Get-ADUser <sAMAaccountName> -Properties thumbnailphoto , jpegPhoto
$user.thumbnailphoto | Set-Content $env:temp\thumbnailphoto.jpg -Encoding byte 
$user.jpegPhoto | Set-Content $env:temp\jpegPhoto.jpg -Encoding byte

Using PowerShell and ADSI:

$username=$env:username
$domain=$env:userdomain
$temp=$env:temp
$thumbnailphoto = ([ADSISEARCHER]"samaccountname=$($username)").findone().properties.thumbnailphoto
if(!($thumbnailphoto -eq $null)) {$thumbnailphoto | set-content $temp\$domain+$username.thumbnailphoto.jpg -Encoding byte}
$jpegphoto = ([ADSISEARCHER]"samaccountname=$($username)").findone().Properties.jpegphoto
if(!($jpegphoto -eq $null)) {$jpegphoto  | set-content $temp\$domain+$username.jpegPhoto.jpg -Encoding byte}

Search for users with / without photo:

Import-Module ActiveDirectory
Get-ADUser -Filter * -properties thumbnailPhoto | ? {$_.thumbnailPhoto} | select Name
Get-ADUser -Filter * -properties thumbnailPhoto | ? {(-not($_.thumbnailPhoto))} | select Name
Get-ADUser -Filter * -properties jpegPhoto | ? {$_.jpegPhoto} | select Name
Get-ADUser -Filter * -properties jpegPhoto | ? {(-not($_.jpegPhoto))} | select Name

What else can I do with photos uploaded to Active Directory?

Using photos from AD in the Windows menu
“Use AD Photos as Windows 7 User Tiles” ;
"Set Windows 7 User Tile to AD Thumbnail pic . "

Or write your telephone directory as titulusdesiderio " Telephone Directory" with blackjack and a photo.

Also popular now: