How to upload user profile pictures in SharePoint 2010 using PowerShell
· Ingo Karstein
I’ve created a script for uploading user pictures to the SharePoint 2010 User Profile system.
For me it worked very well. But: Use it at your own risk!
Here is the script:
#written by ingo karstein
#region Check x64 host
if( [System.IntPtr]::Size -ne 8) {
Write-Error "Please use a x64 PowerShell host!"
return
}
#endregion
#region Load SharePoint SnapIn and DLL
Remove-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") | out-null
Add-Type -AssemblyName System.DirectoryServices
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
#Check available SharePoint Cmdlets
if( (Get-Command -Noun SPWeb*) -eq $null ) {
Write-Error "SharePoint SnapIn not loaded. SharePoint cmdlets missing!"
return
}
#endregion
cls
#region Config Section
$dom = "sharepoint.local"
$dom2 = "dc=sharepoint, dc=local"
$ad = @("ou=Users,dc=sharepoint,dc=local",
"ou=Users2,dc=sharepoint,dc=local")
$ldapFilter = "(&(objectcategory=user))"
$testuser = $null
#for testing purpose uncomment the following line and add the sAMAccountName of the test user
#$testuser="ikarstein"
#the web application url of the profile system
$personalSiteHost="http://sharepoint.farm/mysitehost"
#the intranet/homepage web application url
$intranetSiteHost="http://sharepoint.farm"
#the path to the user profile pictures. the files must be named like the sAMAccountName and with extension .jpg
# example: ikarstein.jpg
$imagePath="\servershareuser_pictures"
#endregion
$ErrorActionPreference = "Stop"
#This function reads name of the folder where the pictures will be stored
function GetProfilePicturesFolderName {
try {
$a = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Portal")
$name = $a.GetName()
$assemblyRef = new-object System.Reflection.AssemblyName
$assemblyRef.Name = "Microsoft.Office.Server.intl"
$assemblyRef.Version = $name.Version
$assemblyRef.SetPublicKey($name.GetPublicKey())
$assemblyRef.CultureInfo = [System.Globalization.CultureInfo]::InvariantCulture
$assembly = [System.Reflection.Assembly]::Load($assemblyRef)
$s_rmLocStrings = new-object System.Resources.ResourceManager ("Microsoft.Office.Server.Strings", $assembly)
$s_rmLocStrings.GetString("UserProfile_UploadPicture_FolderName")
} catch {
$null
}
}
#This function reads name of the SharePoint list where the pictures will be stored
function GetProfilePicturesListName {
try {
$a = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Portal")
$name = $a.GetName()
$assemblyRef = new-object System.Reflection.AssemblyName
$assemblyRef.Name = "Microsoft.Office.Server.intl"
$assemblyRef.Version = $name.Version
$assemblyRef.SetPublicKey($name.GetPublicKey())
$assemblyRef.CultureInfo = [System.Globalization.CultureInfo]::InvariantCulture
$assembly = [System.Reflection.Assembly]::Load($assemblyRef)
$s_rmLocStrings = new-object System.Resources.ResourceManager ("Microsoft.Office.Server.Strings", $assembly)
$s_rmLocStrings.GetString("MyPage_MyLists_ProfilePicture_Text")
} catch {
$null
}
}
#This function returns the object for the profile picture list
function GetProfilePicturesList {
try {
$profilePicturesListName = GetProfilePicturesListName
$profileWeb.Lists | ? { $_.get_BaseTemplate() -eq 0x6d -and $_.get_Title() -ieq $profilePicturesListName }
} catch {
$null
}
}
#This function removes special characters from the file name
function ConvertToLegalFileName($inputName, $replacementChar) {
$l = $inputName.Length;
$builder = New-Object System.Text.StringBuilder($inputName)
for ($i = 0; $i -lt $l; $i++) {
if ([Microsoft.SharePoint.Utilities.SPUrlUtility]::IsLegalCharInUrl($inputName[$i]) -ne $true)
{
$builder.set_chars($i, $replacementChar)
}
}
return $builder.ToString()
}
#This function returns the sub folder for pictures in the picture list
function GetSubfolderForPictures {
$folderName = GetProfilePicturesFolderName
try {
$subfolder = $profilePicturesList.get_RootFolder().Get_SubFolders().get_Item($folderName)
if( $subfolder -eq $null ) {
$subfolder = $profilePicturesList.get_RootFolder()
}
} catch {
try {
$subfolder = $profilePicturesList.get_RootFolder().get_SubFolders().Add($folderName)
} catch {
$subfolder = $null
}
}
return $subfolder
}
#this function returns *multiple* objects:
# 1. the MethodInfo object for "CreateThumbnail"
# 2. the size of the large thumbnal picture
# 3. the size of the medium thumbnail picture
# 4. the size of the small thumbnail picture
function InitializeUserProfilePhotosType {
$a = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles")
$userPofilePhotosType = $a.GetType("Microsoft.Office.Server.UserProfiles.UserProfilePhotos")
#outputs:
$userPofilePhotosType.GetMethod("CreateThumbnail", [System.Reflection.BindingFlags]([System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::NonPublic))
$userPofilePhotosType.InvokeMember("LargeThumbnailSize", [System.Reflection.BindingFlags]([System.Reflection.BindingFlags]::Public -bor [System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::GetProperty ), $null, $null, @() )
$userPofilePhotosType.InvokeMember("MediumThumbnailSize", [System.Reflection.BindingFlags]([System.Reflection.BindingFlags]::Public -bor [System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::GetProperty ), $null, $null, @() )
$userPofilePhotosType.InvokeMember("SmallThumbnailSize", [System.Reflection.BindingFlags]([System.Reflection.BindingFlags]::Public -bor [System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::GetProperty ), $null, $null, @() )
}
#this function returns a MethodInfo object for "EnsureTrailingSlash" method
function InitializePersonalSpaceGlobalType {
$a = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles")
$personalSpaceGlobalType = $a.GetType("Microsoft.Office.Server.WebControls.UserProfileHelper.PersonalSpaceGlobal")
#outputs:
$personalSpaceGlobalType.GetMethod("EnsureTrailingSlash", [System.Reflection.BindingFlags]([System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::NonPublic))
}
#thid function returns a MethodInfo object for "GetSmallThumbnailUrl" method
function InitializeUserProfileGlobalType {
$a = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles")
$userProfileGlobalType = $a.GetType("Microsoft.Office.Server.UserProfiles.UserProfileGlobal")
#outputs:
$userProfileGlobalType.GetMethod("GetSmallThumbnailUrl", [System.Reflection.BindingFlags]([System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::NonPublic))
}
#this function creates an absolute url for the given relative url
function MakeFullUrl {
param($url)
return "$($temp)$($Url)"
}
#this function reads the users from the Active Directory
function GetUsers {
$ctype = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $dom, $dom2
$l = @()
$ad | % { $domain = [ADSI]("LDAP://"+$_)
$filter = $ldapFilter
$ds = new-object System.DirectoryServices.DirectorySearcher($domain,$filter)
$users = $ds.Findall()
$users | % { $l = $l + $_ }
}
$identityParam = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
$m = @()
if( $testuser -ne $null ) {
Write-Host "Test mode!" -ForegroundColor Red
}
$l | % {
$san = $_.properties["samaccountname"]
if( $testuser -eq $null -or $testuser -ieq $san) {
$m = $m + $san[0]
}
}
#output:
$m
}
$profileSite = (Get-SPSite $personalSiteHost)
$profileWeb = $profileSite.RootWeb
$site=(Get-SPSite $intranetSiteHost)
$sc = [Microsoft.Office.Server.ServerContext]::GetContext($site)
$upm = New-Object "Microsoft.Office.Server.UserProfiles.UserProfileManager" -ArgumentList ($sc)
$mysiteHostUrl = $upm.MySiteHostUrl
$ensureTrailingSlashMethod = (InitializePersonalSpaceGlobalType)
$mysiteHostUrl = $ensureTrailingSlashMethod.Invoke($null, @(, $mysiteHostUrl))
$createThumbnailMethod, $largeThumbnailSize, $mediumThumbnailSize, $smallThumbnailSize = (InitializeUserProfilePhotosType)
$getSmallThumbnailUrlMethod = (InitializeUserProfileGlobalType)
$profilePicturesList = GetProfilePicturesList
$profilePicturesFolder = GetSubfolderForPictures
$users=(GetUsers)
$users | % {
$currentUser = $_
Write-Host "Processing user $($currentUser)"
$up=$null
try {
$up = $upm.GetUserProfile($currentUser)
} catch {
#this exception handler may be called for "renamend" users: In the AD the account name was changed but not in the SharePoint User Profil system
$e=$upm.GetEnumerator()
$e.reset()
while( $e.movenext() ) {
$u = $e.current
if( $u["UserName"] -ieq $currentUser ) {
$up = $u
break
}
}
}
if( $up -ne $null ) {
Write-Host " User found in profile store"
$picture = [byte[]](Get-Content -path "$($imagePath)$($currentUser).jpg" -Encoding Byte -ErrorAction SilentlyContinue)
if( $picture -ne $null ) {
Write-Host " User picture found: ""$($imagePath)$($currentUser).jpg"""
$dstFileName = (ConvertToLegalFileName $up["AccountName"].Value.ToString() "_")
$flag = $profileWeb.get_AllowUnsafeUpdates()
try
{
$profileWeb.set_AllowUnsafeUpdates($true)
try
{
$stream = $bitmap = $ps = $null
try {
$stream = New-Object System.IO.MemoryStream @(, $picture)
if( $stream -ne $null ) {
$bitmap = New-Object System.Drawing.Bitmap ($stream, $true)
if( $bitmap -ne $null ) {
Write-Host " starting photo creation..."
$p = ([System.Drawing.Bitmap]$bitmap, $largeThumbnailSize, $largeThumbnailSize, [Microsoft.SharePoint.SPFolder]$profilePicturesFolder, "$($dstFileName)_LThumb.jpg")
$file = $createThumbnailMethod.Invoke($null, $p )
Write-Host " large thumnail created..."
$p = ([System.Drawing.Bitmap]$bitmap, $smallThumbnailSize, $smallThumbnailSize, [Microsoft.SharePoint.SPFolder]$profilePicturesFolder, "$($dstFileName)_SThumb.jpg")
$file = $createThumbnailMethod.Invoke($null, $p )
Write-Host " small thumnail created..."
$p = ([System.Drawing.Bitmap]$bitmap, $mediumThumbnailSize, $mediumThumbnailSize, [Microsoft.SharePoint.SPFolder]$profilePicturesFolder, "$($dstFileName)_MThumb.jpg")
$file = $createThumbnailMethod.Invoke($null, $p )
Write-Host " medium thumnail created..."
$mediumUrl = $profileSite.MakeFullUrl( (MakeFullUrl $file.get_Url()) )
$smallThumbUrl = $getSmallThumbnailUrlMethod.Invoke($null, ([string]$mediumUrl))
[Microsoft.SharePoint.SPSecurity]::RunWithElevatedPrivileges( {
$ps = $up.PersonalSite
if( $ps -ne $null ) {
$ps.get_RootWeb().set_SiteLogoUrl($smallThumbUrl)
$ps.get_RootWeb().Update()
}
$up["PictureURL"].Value = $mediumUrl
$up.Commit()
} );
}
}
} catch {
Write-Host " error occured!"
Write-Error $Error[0]
} finally {
if( $bitmap -ne $null ) {
$bitmap.dispose()
}
if( $stream -ne $null ) {
$stream.close()
$stream.dispose()
}
}
} catch {
}
} finally{
$profileWeb.set_AllowUnsafeUpdates($flag)
}
} else {
Write-Host " Users picture not found" -ForegroundColor Red
}
} else {
Write-Host " User not found in profile store" -ForegroundColor Red
}
} 6 comments
SharePointGuru14 Feb 25, 2011
A shorter cleaner powershell script to do this can be found here: http://licomputersource.com/Blog/2010/12/uploading-user-profile-pictures-programmatically/
It also walks you through step by step
ikarstein Mar 3, 2011
Shorter: yes! - Cleaner: yes! - BUT... My solution doest the picture upload the same way as the SharePoint itself does this job!!! Your solution does not upload pictures to the dedicated pictures list and it does not create 3 versions of the picture: large, medium and small, e.g. used by "Organization Browser".
SharePointguru14 Mar 3, 2011
My stores the pictures in the picture library and creates the 3 resized images for use within the org browser, outlook etc. That is what the command below does.
Update-SPProfilePhotoStore –MySiteHostLocation “http:///”
Did you try it and have trouble getting it to work?
SharePointGuru14 Mar 15, 2011
Just wanted to ask you to update the link you have in my last post. I changed the url around to be a little cleaner should read http://licomputersource.com/Blog/2010/12/uploading-user-profile-pictures-programmatically/
thanks
Daniel May 12, 2011
Very very good script!!!!
But i found a small issue with following two functions "GetProfilePicturesFolderName" and "GetProfilePicturesListName". These returns in my case not the correct values. I think the reason is, that i installed SharePoint in German with English language packs. Our MySite is provisioned in english language. Therefor my list called "User Photos" and my Picture Folder "Profile Pictures". But unfortunately your functions returns the german values ;)
ikarstein May 12, 2011
Hi Daniel!
Thanks for your comment! - Very interesting! - I will check the script using your scenario.
Kind regards
Ingo