Updated: November 12, 2017 | 82 comments | Tags: Active Directory, GPO, PowerShell, Profile, usertile, VBs, Windows 10
I’ve been working on implementing Windows 10 at a company.
They wanted to import a photo of all the users to the Active Directory, and have all the other systems pull the pictures from it. I primarily focused on Windows clients, Lync and SharePoint.
Goal
Our goal is to have Windows 8 and 10 clients pull the pictures from Active Directory to the users local profiles.
1. Importing the pictures to Active Directory
Now there are several approaches for this. Getting the pictures into AD I prefer using PowerShell.
If you’re more into GUI style I can recommend this AD Photo Edit.
2. Create the required scripts
You need a (startup) script to download the data from Active Directory and convert them to JPEG-files.
The script then proceeds to set these images as your local users profile picture/tile.
The PowerShell-script I’m using was originally written by Jordan. I modified it for better functionality and to make it work better with Windows 10.Set-ADPicture.ps1PowerShell
<#
.SYNOPSIS
Set-ADPicture.ps1
Written by Joakim at Jocha AB, http://jocha.se
.DESCRIPTION
Version 1.3 - Updated 2016-02-13
This script downloads and sets the Active Directory profile photograph and sets it as your profile picture in Windows.
Remember to create a defaultuser.jpg in \\domain\netlogon\
2016-02-13 : Slightly adjusted.
2015-11-12 : Added all picture sizes for Windows 10 compatibility.
#>
[CmdletBinding(SupportsShouldProcess=$true)]Param()
function Test-Null($InputObject) { return !([bool]$InputObject) }
# Get sid and photo for current user
$user = ([ADSISearcher]"(&(objectCategory=User)(SAMAccountName=$env:username))").FindOne().Properties
$user_photo = $user.thumbnailphoto
$user_sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
# Continue if an image was returned
If ((Test-Null $user_photo) -eq $false) {
Write-Verbose "Photo exists in Active Directory."
}
# If no image was found in profile, use one from network share.
Else {
Write-Verbose "No photo found in Active Directory for $env:username, using the default image instead"
$user_photo = [byte[]](Get-Content "\\$env:USERDNSDOMAIN\NETLOGON\defaultuser.jpg" -Encoding byte)
}
# Set up image sizes and base path
$image_sizes = @(32, 40, 48, 96, 192, 200, 240, 448)
$image_mask = "Image{0}.jpg"
$image_base = "C:\ProgramData\AccountPictures"
# Set up registry
$reg_base = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AccountPicture\Users\{0}"
$reg_key = [string]::format($reg_base, $user_sid)
$reg_value_mask = "Image{0}"
If ((Test-Path -Path $reg_key) -eq $false) { New-Item -Path $reg_key }
# Save images, set reg keys
Try {
ForEach ($size in $image_sizes) {
# Create hidden directory, if it doesn't exist
$dir = $image_base + "\" + $user_sid
If ((Test-Path -Path $dir) -eq $false) { $(mkdir $dir).Attributes = "Hidden" }
# Save photo to disk, overwrite existing files
$file_name = ([string]::format($image_mask, $size))
$path = $dir + "\" + $file_name
Write-Verbose " saving: $file_name"
$user_photo | Set-Content -Path $path -Encoding Byte -Force
# Save the path in registry, overwrite existing entries
$name = [string]::format($reg_value_mask, $size)
$value = New-ItemProperty -Path $reg_key -Name $name -Value $path -Force
}
}
Catch {
Write-Error "Cannot update profile picture for $env:username."
Write-Error "Check prompt elevation and permissions to files/registry."
}
To make this script run hidden I resolved to creating a VBs wrapper that would silently execute the scriptSet-ADPicture.vbsVisual Basic
'
' Title: Set-ADPicture.vbs
' Author: Joakim at Jocha AB, http://jocha.se
' Modified: 2016-02-13
'
On Error Resume Next
command = "powershell.exe -Noninteractive -ExecutionPolicy Bypass -Noprofile -File \\domain.local\NETLOGON\Set-ADPicture.ps1"
set shell = CreateObject("WScript.Shell")
shell.Run command,0
Now put both these scripts in your NETLOGON-folder (ie. \\domain.local\NETLOGON).
3. Setting up the GPO
Open the Group Policy Management Console and create a new GPO. Lets call it “Pictures”.
Edit it and go to
Computer Configuration > Policies > Windows Settings > Security Settings > Registry
Right Click on Registry and select Add Key. Then Add the Key:
MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AccountPicture\Users
Give Full Permission on this key (and sub keys) to <Domain>\Users.
Also make sure you have selected Replace Existing permission on all sub keys with inheritable permissions. Otherwise the script will not be able to update the necessary registry values.
4. Setting up the Task schedule
To run the function there are a couple of different approaches. You could either execute it from the “Logon Scripts” function in a Group policy or via Task Scheduler for example. Since you probably know how to set up a logon script, I’ll demo how to set up a scheduled job…
In the same Group Policy object as above, go to:
User Configuration > Preferences > Control Panel Settings > Scheduled Tasks
Right Click and select New Sheduled Task (At lest Windows 7) option.
Under the General tab Set Name as: Set-ADPicture
Under the General tab, set name to: Set-ADPicture
Under the Triggers tab, create a new trigger and select Begin the task: At Login, Any User
Under the Actions tab:
Create New Action Select Action “Start Program”.
From Program Script Option.
Select the VBs-script from NETLOGON.
Under the Conditions tab:
I prefer to enable Start only if the following network connection in available to make sure it does not waste resources if disconnected from the network.
5. Target the GPO
All the settings are now set. Go back to the Group Policy console and create your target links to the proper OUs.
Please let me know if I’ve missed something or if its not working for you.