locked
Programmatically Upload Pictures to SharePoint Profile Picture Store using Powershell RRS feed

  • Question

  • I'm trying to create a powershell script that will bulk upload pictures to the SharePoint Profile Picture Store located in a "http://sp2010/my/User Photos/Profile Pictures".  I found Chris Johnson's blog post ( http://blogs.msdn.com/b/cjohnson/archive/2010/05/08/sharepoint-2010-office-2010-and-profile-pictures.aspx )  extremely useful.  However, the SPUtils.ps1 that is referenced on his site doesn't seem to support uploading to the "Profile Pictures" folder within the "User Photos" picture library at "http://sp2010/my/User Photos".  My account has full control of the "User Photos" picture library and the "Profile Pictures" folder, and I can upload to the "User Photos", root directory with no problems.  The file fails to upload to the "Profile Pictures" folder.

    Currently my Powershell script processes a folder of pictures.  First, it pulls the file name and does some manipulations to retrieve the employee number of the employee.  Second, it performs an active directory search to get the employee's user name.  Third, it resizes the photo to match the small, medium, and large thumbnails generated by a traditional manual upload of a photo from the user's edit profile page.  After each creation of the resized picture it uploads the picture to the sharepoint site.  Next, it sets the user profile to use the medium sized thumbnail photo.  Finally, it runs the "Update-SPProfilePictureStore -MySiteHostLocation "http://sp2010/my" which is supposed to automatically resize all the thumbnails in "http://sp2010/my/User Photos/Profile Pictures", but I have yet to see it work after manually uploading a file and setting it as a user's profile picture.

    Below is some code from the SPUtils.ps1 file located at Chris Johnson's blog page ( http://blogs.msdn.com/b/cjohnson/archive/2010/05/08/sharepoint-2010-office-2010-and-profile-pictures.aspx ).  Again I would like to be able to upload pictures to a folder within a picture library.

    Any help is greatly appreciated.

    Thanks

     

    function GetSPFile($libraryInstance, $fileName)
    {
        $fileName = (ToSimpleString -value $fileName -removeSpaces $false);

        foreach($file in $libraryInstance.RootFolder.Files)
        {
            $itemName = (ToSimpleString -value $file.Name -removeSpaces $false);
            if ($fileName -eq $itemName)
            {
                return $file;
            }
        }
        return $null;
    }


    function UploadSPFile([string]$url, [string]$libraryName, [string]$filePath, [System.Text.StringBuilder]$verbose = $null)
    {
        try
        {
            [Microsoft.SharePoint.SPDocumentLibrary]$lib = (GetSPDocumentLibrary -url $url -libraryName $libraryName);
            if ($lib -eq $null)
            {
                throw (([string]'Cannot find document library "') + ([string]$libraryName) + ([string]'" at url "') + ([string]$url) + ([string]'"!'));
            }

            $bytes = [System.IO.File]::ReadAllBytes($filePath);
            $fileName = [System.IO.Path]::GetFileName($filePath);

            [Microsoft.SharePoint.SPFile]$file = GetSPFile -libraryInstance $lib -fileName $fileName;
           
            if ($file -eq $null)
            {
                if ($verbose -ne $null)
                {
                    [void]$verbose.AppendLine("Uploading File...");
                }
                $file = $lib.RootFolder.Files.Add($fileName, $bytes);
            }
            else
            {
                if ($verbose -ne $null)
                {
                    [void]$verbose.AppendLine("File Exists, overwriting...");
                }
                $file.SaveBinary($bytes);
            }
           
            if ($verbose -ne $null)
            {
                [void]$verbose.AppendLine(($bytes.Length.ToString()) + ([string]" bytes written!"));
            }

            return $file;
        }
        catch
        {
            if ($verbose -ne $null)
            {
                [void]$verbose.AppendLine(([string]'Error: Upload to document library "') + ([string]$libraryName) + ([string]'" at "') + ([string]$url) + ([string]'" or file "') + ([string]$filePath) + ([string]'" failed!'));
                [void]$verbose.AppendLine([string]'Error: ' + [string]$error[1]);
            }
        }
       
        return $null;
    }

    Wednesday, August 18, 2010 7:23 PM

Answers

  • Hi Bill

    It sounds like your SharePoint and AD sync might not be configured properly.  This would cause your pictureURL to get wiped out once it tried to sync again.  AD stores the thumbnailphoto as a byte array whereas the SharePoint pictureURL is an actual URL; this difference in data types causes problems with the synchronization process.  A sync of AD to SharePoint will not work for the picture, but a SharePoint to AD will work. 

    You can change the synchronization to not include the picture and it can still pull everything from AD.

    Also I used code from http://poshcode.org/621 to resize my pictures. 

    Hope that helps

    Friday, August 20, 2010 5:59 PM

All replies

  • I have been hammering on the same issue and have tried every piece of powershell I can find and customize, nothing has worked...

    I finally created 3 directories and used a free utility called PictureResize.exe to create the 3 sizes from the originals then went into the Profile Pictures folder via the browser, once there you can click Upload->Upload Multiple Pictures. If you have the Office Picture Manager loaded (we use Office 2010) it will allow you to select all of the pictures in each folder and upload them to the Profile Pictures folder where they belong. NOTE: Uploading a single 144x144 picture here DOES NOT cause SharePoint to create the other two thumbnails! You must upload all 3 sizes.

    The only way I have found that works is to manually do each user via SharePoint mysite interface, i.e. Edit the profile within mysite, which is not going to happen here. We are not going to allow users to edit and upload thier own pictures, several users submitted a 16MB (yes MB) picture they wanted to use.

    At this point I cannot figure out how to assign the URL to the pictureURL property and make it stick, I can set it but then sharepoint just drops it after a few minutes. This means if I schedule the Profile Manager to sync with AD then SharePoint clears out the AD thumbnailPhoto attribute and I am back to blank user photos...

    I believe my current issue might be caused by the fact that I am trying to set all this up before we roll out, our users have not created profiles as of yet.

    If anyone has found a method to get the thumbnail into the correct location and assign the pictureURL and thumbnailPhoto attributes please chime in.
    I am not looking for any hacks that place the pictures into another location and runs some external sync, only interested in doing this the correct way so that the pictures are in the proper location and the user profile manager can sync to AD.

     

    Thanks!

     

     

    Friday, August 20, 2010 3:35 PM
  • Hi Bill

    It sounds like your SharePoint and AD sync might not be configured properly.  This would cause your pictureURL to get wiped out once it tried to sync again.  AD stores the thumbnailphoto as a byte array whereas the SharePoint pictureURL is an actual URL; this difference in data types causes problems with the synchronization process.  A sync of AD to SharePoint will not work for the picture, but a SharePoint to AD will work. 

    You can change the synchronization to not include the picture and it can still pull everything from AD.

    Also I used code from http://poshcode.org/621 to resize my pictures. 

    Hope that helps

    Friday, August 20, 2010 5:59 PM
  • Bill,

    I had the same issue, but worked around it by creating my own .ps1 script to upload photos to my "User Photos"\"Profile Pictures" folder.  Now, I'm trying to figure out how to do the 3 sizes on the photos in this folder and a For each... script that will loop through each of the photos and set the pictureUrl.  I can set the pictureUrl one by one, but that's not feasible.  Here's the code I used:

    #Setup default variables
    $webUrl = "<enter your my site web url here"
    $picLibraryName = "User Photos"
    $picFolderName = "Profile Pictures"
    $localFolderPath = "c:\temp\photos\" -- change to wherever your photos are stored
     

    #Get web and picture library folder that will store the pictures
    $web = Get-SPweb $webUrl
    $picFolder = $web.Folders["User Photos"].SubFolders["Profile Pictures"]
     if(!$picFolder)
     {
      Write-Host "Picture Library Folder not found"
      return
     }

    #Attach to local folder and enumerate through all files
    $files = ([System.IO.DirectoryInfo] (Get-Item $localFolderPath)).GetFiles() | ForEach-Object {

        #Create file stream object from file
        $fileStream = ([System.IO.FileInfo] (Get-Item $_.FullName)).OpenRead()
        $contents = new-object byte[] $fileStream.Length
        $fileStream.Read($contents, 0, [int]$fileStream.Length);
        $fileStream.Close();

        write-host "Copying" $_.Name "to" $picFolder.Title "in" $web.Title "..."

        #Add file
        $spFile = $picFolder.Files.Add($picFolder.Url + "/" + $_.Name, $contents, $true)
        $spItem = $spFile.Item

        #Check in file to picture library
        #MinorCheckIn=0, MajorCheckIn=1, OverwriteCheckIn=2
        #$spFile.CheckIn("File copied from " + $filePath, 1)
        #if ($spFile.CheckOutStatus -eq "None") { write-host $spfile.Name"checked in" }
       
       
        #Approve file
        #$spFile.Approve("File automatically approved after copying from " + $localFolderPath)
        #if ($spItem["Approval Status"] -eq 0) { write-host $spfile.Name"approved" }
       
        }

    If you can figure out the last 2 sections for checking the files in and approving them, let me know; otherwise, I've left them commented out.

    Tuesday, September 14, 2010 9:36 PM
  • Bill,

    Thanks for posting this, I saw Chris Johnson's blog as well, and although it was helpful, it wasnt exactly what I am looking for. Can you share your script that you are talking about above? The one mentioned here

     

    "Currently my Powershell script processes a folder of pictures.  First, it pulls the file name and does some manipulations to retrieve the employee number of the employee.  Second, it performs an active directory search to get the employee's user name.  Third, it resizes the photo to match the small, medium, and large thumbnails generated by a traditional manual upload of a photo from the user's edit profile page.  After each creation of the resized picture it uploads the picture to the sharepoint site.  Next, it sets the user profile to use the medium sized thumbnail photo.  Finally, it runs the "Update-SPProfilePictureStore -MySiteHostLocation "http://sp2010/my" which is supposed to automatically resize all the thumbnails in "http://sp2010/my/User Photos/Profile Pictures", but I have yet to see it work after manually uploading a file and setting it as a user's profile picture."

     

    It would greatly help my situation, and sounds exactly what I need.

     

    TracK18, thanks for sharing your script it is very close to what I need. I currently need to resize the photos as well.

     

    Thanks,

    Garet

     

    If you could share it, I would very much appreciate it.

    Friday, October 1, 2010 4:43 AM
  • TracK18: "creating my own .ps1 script" - looks suspiciously like mine at http://get-spscripts.com/2010/07/upload-multiple-files-into-document.html :-)

    I'll be writing up an article on uploading My Site pictures using PowerShell soon

    Monday, October 11, 2010 9:21 AM
  • I have published an article on my blog today showing how to upload multiple user profile pictures/photos in SharePoint 2010 using PowerShell: http://get-spscripts.com/2010/12/upload-multiple-user-profile.html 

    Phil

     


    Phil Childs http://get-spscripts.com
    • Proposed as answer by Phil Childs Wednesday, January 19, 2011 10:03 PM
    Wednesday, December 1, 2010 12:21 AM
  • Hi Phil,

    i'm trying to manual update user profile photo to sharepoint 2010, but is not working.

    Here are the steps:

    1. Manual upload on User Photos (not profile pictures) of the file company_username.jpg

    2. Wait for 2 minutes, then on sharepoint 2010 (without CU of october ) i ran the command Update-spprofilephotostore -mysitehostlocation http://intranetsite/my ... no error, and prompt again

    The photos are not copied into Profile Picture folder.... Is this happening because the system misses the Cumulative Update of October, republished in December? Is it safe now to install it, or it can break the User Profile like the previous version?

    Thank you for your help

    Andrea

    Tuesday, January 18, 2011 2:43 PM
  • Andrea,

    It shouldn't be anything to do with the cumulative update, although from memory I think I was running October's when I tested and wrote the article.

    The Update-SPProfilePhotoStore cmdlet is a strange one, but I can only report on what I found when I wrote my blog article on using it - that, for me, I had to wait 60 seconds between uploading the photos and running the cmdlet before the pictures appeared in the Profile Pictures library.

    Have you definitely set the "PictureURL" value in the user profile for the person related to the image before uploading it? It will not work by uploading the picture alone - the user profile for the person must also be set.

    Phil


    Phil Childs http://get-spscripts.com
    Wednesday, January 19, 2011 10:09 PM
  • Hi Andrea

    I had the exact same question. Did you manage to get it working?

    --------

    Phil

    What do you mean by:
    "Have you definitely set the "PictureURL" value in the user profile for the person related to the image before uploading it? It will not work by uploading the picture alone - the user profile for the person must also be set."
    Can you set this value, without actually uploading an image?

    Thanks

    Thursday, February 17, 2011 11:10 AM
  • a good write with the full script and documented process can be found here:

    http://licomputersource.com/Blog/2010/12/uploading-user-profile-pictures-programmatically/

     

    Friday, February 25, 2011 4:00 AM
  • Have you tried the PowerShell command Update-SPProfilePhotoStore –MySiteHostLocation “http://<my site host url>/” after you uploaded your photos?

    This should "create" all 3 types of photos starting from the one uploaded.

    Friday, April 1, 2011 10:49 AM
  • This is a simple example of taking a photo and uploading it into the User Profile database with the Powershell.

    After reading a lot of articles and trying several approaches, I thought I would post my solution.  It is a combination of the other posts - so thanks for everyone's input.  This solution is short and simple. 

    To see how your system is configured, it may be helpful to look at the Configuration database.  The PropertyList table should have a PictureURL property.  Note the PropertyID.  Query the ProfileValue table for this PropertyID to see where pictures are stored.  The Profile_Full table also has a PictureURL field. 

    To run the commands below, create a file with a .ps1 extension.  Start the SharePoint Powershell and execute the script with the command  .\<filename>
    After this executes, execute the command  Update-SPProfilePhotoStore –MySiteHostLocation “http://<my site host url>/”
    After running the Update command, this folder should have three new photos for each user - ending in _LThumb, _MThumb and _SThumb.

    function GetSPSite($url)
    {
        [Microsoft.SharePoint.SPSite]$site = New-Object "Microsoft.SharePoint.SPSite" -ArgumentList $url
        return $site;
    }

    function GetSpContext($url)
    {
        [Microsoft.SharePoint.SPSite]$site = GetSPSite -url $url   
        return [Microsoft.Office.Server.ServerContext]::GetContext($site);
    }

    function GetProfileManager($url)
    {
        [Microsoft.Office.Server.ServerContext]$ctx = GetSpContext -url $url
        [Microsoft.Office.Server.UserProfiles.UserProfileManager]$upm = New-Object "Microsoft.Office.Server.UserProfiles.UserProfileManager" -ArgumentList $ctx
       
        return $upm;
    }

    $siteUrl = http://mysharepointsite
    $upm = GetProfileManager -url $siteUrl

    $name = "mydomain\myuserid"
    $pic = "http://mysharepointsite/User%20Photos/Profile%20Pictures/Debbie.jpg"
    $up = $upm.GetUserProfile($name);
    $up.get_Item("PictureUrl").Value = $pic
    $up.commit()

    Tuesday, July 26, 2011 4:52 PM