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 } }
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
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”.
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?
Pingback: Uploading user profile picture in SharePoint 2010 « Virtualize SharePoint, SharePoint Virtualization, Virtualization Tips
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
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 😉
Hi Daniel!
Thanks for your comment! – Very interesting! – I will check the script using your scenario.
Kind regards
Ingo
Pingback: Sharepoint 2010 Mass Uploading profile pictures programatically «sreesp sreesp