Forum Discussion

Deepthi Yathiender's avatar
Deepthi Yathiender
Brass Contributor
Jun 16, 2017

Profile Photo Sync SPO

As admin, I have added profile photos for everyone in my org through the O365 admin portal. The photos are seen everywhere. Except on SharePoint. I am unable to upload photos for people on SPO. I have read in other posts that the photos are synced when each user visits their Delve page at least once. Now, I cannot expect every user to go to their Delve page to sync the profile photos to SharePoint. Is there another way for the admin to do this?

 

Many thanks for any help!

  • adrianhalid's avatar
    adrianhalid
    Copper Contributor

    I thought this might help others.

    Based on a previous post I created this script to work with O365 with MFA enabled.

     

    This PowerShell script will allow you to sync a user profile photo from Exchange Online to Sharepoint Online.

    You can select a single email address or choose "All"

     

    EDIT: Added Try-Catch block around section for some error handling.

     

    #Add references to SharePoint client assemblies and authenticate to Office 365 site – required for CSOM
    Add-Type -AssemblyName System.Drawing
    
    Function UploadImage ()
    {
    	Param(
    	  [Parameter(Mandatory=$True)]
    	  [String]$SiteURL,
    
    	  [Parameter(Mandatory=$True)]
    	  [String]$SPOAdminPortalUrl,
    
    	  [Parameter(Mandatory=$True, HelpMessage="Enter user email address or All for all mailboxes")]
    	  [String]$UserEmail
    
    	)
    
    	#Defualt Image library and Folder value 
    	$DocLibName ="User Photos"
    	$foldername="Profile Pictures"
    
        Connect-ExchangeOnline
        $siteConnection = Connect-PnPOnline -Url $SiteURL –Interactive -ReturnConnection
    
        #NOTE: there is a bug in Set-PnPUserProfileProperty in which the ConnectPnPOnline must connect with the UseWebLogin option 
        # https://github.com/pnp/powershell/issues/277
        $adminConnection = Connect-PnPOnline -Url $SPOAdminPortalUrl –UseWebLogin -ReturnConnection
    
    	$spoimagename = @{"_SThumb" = "48"; "_MThumb" = "72"; "_LThumb" = "200"}
    
    
        $allUserMailboxes = Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox
    
        Foreach($mailbox in $allUserMailboxes)
        {
    
            if(($mailbox.PrimarySmtpAddress -eq $UserEmail) -or ($UserEmail -eq "All")){
    
                Write-Host "Processing " $mailbox.PrimarySmtpAddress
    
                try{
    		        #Download Image from Exchange online 
                    $photo = Get-UserPhoto -Identity $mailbox.Identity
    		        Write-Host "Exchange online image downloaded successful for" $mailbox.PrimarySmtpAddress
    
    		        $username = $mailbox.PrimarySmtpAddress.Replace("@", "_").Replace(".", "_")
    
    		        $Extension = ".jpg"
    		        Foreach($imagename in $spoimagename.GetEnumerator())
    		        {
    			        #Covert image into different size of image
                        $ms = new-object System.IO.MemoryStream(,$photo.PictureData)
    			        $img = [System.Drawing.Image]::FromStream($ms)
    			        [int32]$new_width = $imagename.Value
    			        [int32]$new_height = $imagename.Value
    			        $img2 = New-Object System.Drawing.Bitmap($new_width, $new_height)
    			        $graph = [System.Drawing.Graphics]::FromImage($img2)
    			        $graph.DrawImage($img, 0, 0, $new_width, $new_height)
    
    			        #Covert image into memory stream
    			        $stream = New-Object -TypeName System.IO.MemoryStream
    			        $format = [System.Drawing.Imaging.ImageFormat]::Jpeg
    			        $img2.Save($stream, $format)
    			        $streamseek=$stream.Seek(0, [System.IO.SeekOrigin]::Begin)
    
    			        #Upload image into sharepoint online
    			        $FullFilename=$username+$imagename.Name+$Extension
                        Add-PnPFile -Connection $siteConnection -Folder "User Photos/Profile Pictures" -FileName $FullFilename -Stream $stream                                
    
    		        }
    		        Write-Host "SharePoint online image uploaded successful for" $mailbox.PrimarySmtpAddress
    		        #Change user Profile Property in Sharepoint onlne 
    		        $PictureURL=$SiteURL+$DocLibName+"/"+$foldername+"/"+$username+"_MThumb"+$Extension
    
                    Set-PnPUserProfileProperty -Connection $adminConnection -Account $mailbox.PrimarySmtpAddress -PropertyName PictureURL -Value $PictureURL
    
                    Set-PnPUserProfileProperty -Connection $adminConnection -Account $mailbox.PrimarySmtpAddress -PropertyName SPS-PicturePlaceholderState -Value 0
    
                    Set-PnPUserProfileProperty -Connection $adminConnection -Account $mailbox.PrimarySmtpAddress -PropertyName SPS-PictureExchangeSyncState -Value 0
    
                    Set-PnPUserProfileProperty -Connection $adminConnection -Account $mailbox.PrimarySmtpAddress -PropertyName SPS-PictureTimestamp -Value 63605901091
    
    		        Write-Host "Image processed successfully and ready to display for" $mailbox.PrimarySmtpAddress
                }catch{
                    $ErrorMessage = $_.Exception.Message
                    Write-Host "Failed to process " $mailbox.PrimarySmtpAddress -ForegroundColor red
                    Write-Host $ErrorMessage -ForegroundColor red
                }
    	    }        
    
        }
    
    }
    
    #Input parameter
    $siteUrl="https://company-my.sharepoint.com/"
    $SPOAdminPortalUrl = "https://company-admin.sharepoint.com/"
    
    uploadimage -SiteURL $siteUrl -SPOAdminPortalUrl $SPOAdminPortalUrl

     

     

    • Deepthi Yathiender's avatar
      Deepthi Yathiender
      Brass Contributor

      So, I set the user photo using Powershell. See screenshot. It ran without any errors. Now, when I go the sharepoint admin page, the photo for this particular user has not been set. See screenshot. Set-UserPhoto does not seem to set the profile photo in SharePoint. Any further help?




      • SanthoshB1's avatar
        SanthoshB1
        Bronze Contributor

        Following PowerShell script is used to instantly process and display profile picture in Exchange Online and SharePoint Online using “Set-UserPhoto” cmdlet and CSOM.
         
        Before executing the following script, you need to modify the input parameters in the script with your own values as follows,
         
        Input Parameters:
        $siteUrl= "https://tenantname-my.sharepoint.com/"
        $username= "admin@tenantname.onmicrosoft.com"
        $password= "xxxxxxxx"
        $folderpath= "E:\photo"
        $SPOAdminPortalUrl= “https://tenantname-admin.sharepoint.com/”

         

        #Add references to SharePoint client assemblies and authenticate to Office 365 site – required for CSOM
        Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client").location)
        Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.runtime").location)
        Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles").location)
        Add-Type -AssemblyName System.Drawing
        
        Function UpdateUserProfile()
        {
        Param(
          [Parameter(Mandatory=$True)]
          [String]$targetAcc,
        
          [Parameter(Mandatory=$True)]
          [String]$PropertyName,
        
          [Parameter(Mandatory=$False)]
          [String]$Value, 
        
          [Parameter(Mandatory=$True)]
          [String]$SPOAdminPortalUrl,
        
          [Parameter(Mandatory=$True)]
          [System.Net.ICredentials]$Creds
        
        )
        $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SPOAdminPortalUrl)
        $ctx.Credentials = $Creds
        $peopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($ctx)
        $targetAccount = ("i:0#.f|membership|" + $targetAcc)
        $peopleManager.SetSingleValueProfileProperty($targetAccount, $PropertyName, $Value)
        $ctx.ExecuteQuery()
        }
        
        Function UploadImage ()
        {
        Param(
          [Parameter(Mandatory=$True)]
          [String]$SiteURL,
        
          [Parameter(Mandatory=$True)]
          [String]$User,
        
          [Parameter(Mandatory=$False)]
          [String]$Password, 
        
          [Parameter(Mandatory=$True)]
          [String]$Folder,
        
          [Parameter(Mandatory=$True)]
          [String]$SPOAdminPortalUrl
        
        )
        
        #Defualt Image library and Folder value 
        $DocLibName ="User Photos"
        $foldername="Profile Pictures"
        
        #Connect Exchange online 
        
        $secstr = New-Object -TypeName System.Security.SecureString
        $password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
        $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $User, $secstr
        $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/?proxyMethod=RPS -Credential $cred -Authentication Basic -AllowRedirection
        Import-PSSession $Session
        
        $Securepass = ConvertTo-SecureString $Password -AsPlainText -Force
        $Creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User,$Securepass)
        
        #Bind to site collection
        $Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
        $Context.Credentials = $Creds
        
        #Retrieve list
        $List = $Context.Web.Lists.GetByTitle($DocLibName)
        $Context.Load($List)
        $Context.Load($List.RootFolder)
        $Context.ExecuteQuery()
        $ServerRelativeUrlOfRootFolder = $List.RootFolder.ServerRelativeUrl
        
        $uploadFolderUrl=  $ServerRelativeUrlOfRootFolder+"/"+$foldername
        $spoimagename = @{"_SThumb" = "48"; "_MThumb" = "72"; "_LThumb" = "200"}
        #Upload file
        Foreach ($File in (dir $Folder -File))
        {
        
        #Upload image into Exchange online 
        $PictureData = $File.FullName
        $Identity=$File.BaseName
        Set-UserPhoto -Identity $Identity -PictureData ([System.IO.File]::ReadAllBytes($PictureData)) -Confirm:$false
        Write-Host "Exchange online image uploaded successful for" $Identity  
        
        $username=$File.BaseName.Replace("@", "_").Replace(".", "_")
        $Extension = $File.Extension
        Foreach($imagename in $spoimagename.GetEnumerator())
        {
        #Covert image into different size of image
        $img = [System.Drawing.Image]::FromFile((Get-Item $PictureData))
        [int32]$new_width = $imagename.Value
        [int32]$new_height = $imagename.Value
        $img2 = New-Object System.Drawing.Bitmap($new_width, $new_height)
        $graph = [System.Drawing.Graphics]::FromImage($img2)
        $graph.DrawImage($img, 0, 0, $new_width, $new_height)
        
        #Covert image into memory stream
        $stream = New-Object -TypeName System.IO.MemoryStream
        $format = [System.Drawing.Imaging.ImageFormat]::Jpeg
        $img2.Save($stream, $format)
        $streamseek=$stream.Seek(0, [System.IO.SeekOrigin]::Begin)
        
        #Upload image into sharepoint online
        $FullFilename=$username+$imagename.Name+$Extension
        $ImageRelativeURL="/"+$DocLibName+"/"+$foldername+"/"+$FullFilename
        $ModifiedRelativeURL=$ImageRelativeURL.Replace(" ","%20")
        [Microsoft.SharePoint.Client.File]::SaveBinaryDirect($Context,$ModifiedRelativeURL, $stream, $true)
        
        }
        Write-Host "SharePoint online image uploaded successful for" $Identity 
        #Change user Profile Property in Sharepoint onlne 
        $PictureURL=$SiteURL+$DocLibName+"/"+$foldername+"/"+$username+"_MThumb"+$Extension
        
        UpdateUserProfile -targetAcc $Identity  -PropertyName PictureURL  -Value $PictureURL -SPOAdminPortalUrl $SPOAdminPortalUrl -Creds $Creds
        
        UpdateUserProfile -targetAcc $Identity  -PropertyName SPS-PicturePlaceholderState -Value 0 -SPOAdminPortalUrl $SPOAdminPortalUrl -Creds $Creds
        
        UpdateUserProfile -targetAcc $Identity  -PropertyName SPS-PictureExchangeSyncState -Value 0 -SPOAdminPortalUrl $SPOAdminPortalUrl -Creds $Creds
        
        UpdateUserProfile -targetAcc $Identity  -PropertyName SPS-PictureTimestamp  -Value 63605901091 -SPOAdminPortalUrl $SPOAdminPortalUrl -Creds $Creds
        
        Write-Host "Image processed successfully and ready to display for" $Identity
        }
        
        }
        #Input parameter
        $siteUrl="https://tenantname-my.sharepoint.com/"
        $username= "admin@tenantname.onmicrosoft.com" 
        $password= "pass@word1"
        $folderpath= "E:\photo"
        $SPOAdminPortalUrl = "https://tenantname-admin.sharepoint.com/"
        
        uploadimage -SiteURL $siteUrl -User $username -Password $password -Folder $folderpath -SPOAdminPortalUrl $SPOAdminPortalUrl 

Resources