Slow User's Office 365 Photo Exportation

Welcome Forums General PowerShell Q&A Slow User's Office 365 Photo Exportation

This topic contains 5 replies, has 3 voices, and was last updated by

 
Participant
2 months, 3 weeks ago.

  • Author
    Posts
  • #109034

    Participant
    Points: 0
    Rank: Member

    Hi everyone,

    I'm trying to export the office365 photos of all users at my organization, but the whole process is during about 3 hours. We've about 500 users.

    Have something that I can improve at the code, that can turn the process faster?

    $users = Get-ADGroupMember "All Employees" | Select-Object samAccountName
    
    $365Cred = Get-Credential
    $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $365Cred -Authentication Basic -AllowRedirection
    Import-PSSession $Session
    
    foreach ($user in $users){
        $photo = Get-UserPhoto -Identity $($user.SamAccountName) -ErrorAction silentlycontinue
        Set-Content -Value $photo.PictureData "C:\Photos\$($user.samAccountName).jpg" -Encoding byte
         }
    }
    
    Remove-PSSession $Session
    
    
  • #109043

    Participant
    Points: 158
    Helping Hand
    Rank: Participant

    You could attempt to do it as a Workflow so that you can run them them in parallel.

    https://docs.microsoft.com/en-us/powershell/module/psworkflow/about/about_foreach-parallel?view=powershell-5.1

    Since you are in a session, you may need to get all of the photos and then attempt to create the images in parallel. Not sure how much time it would save because you aren't indicating what portion is taking the time.

    Try logic like this:

    $users = Get-ADGroupMember "All Employees" | Select-Object samAccountName
    
    $365Cred = Get-Credential
    $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $365Cred -Authentication Basic -AllowRedirection
    Import-PSSession $Session
    
    $photos = foreach ($user in $users){
        Get-UserPhoto -Identity $($user.SamAccountName) -ErrorAction silentlycontinue
    }
    
    Remove-PSSession $Session
    ...
    
    foreach -parallel ($photo in $photos) {
        Set-Content -Value $photo.PictureData "C:\Photos\$($user.samAccountName).jpg" -Encoding byte
    
    }
    
    • #109100

      Participant
      Points: 0
      Rank: Member

      Sorry for the lack of this information, the Get-UserPhoto consumes about 90% of the time. I did not know this statement, so I was reading about but some doubts have arisen. Should the code loke like this?

      Workflow Get-HBUserPhotos
      {
          param([string[]]$Users)
      
          $photos = foreach ($user in $users){
          Get-UserPhoto -Identity $($user.SamAccountName) -ErrorAction silentlycontinue
          }
          
          foreach -parallel ($photo in $photos) {
              Set-Content -Value $photo.PictureData "C:\Photos\$($user.samAccountName).jpg" -Encoding byte
          }
      }
      

      I appreciate your help!

  • #109112

    Participant
    Points: 158
    Helping Hand
    Rank: Participant

    If Get-UserPhoto is where the bottleneck is, I'm not sure the workflow is going to get you any performance benefit because you have to share that remote session for each parallel process. See this:

    https://stackoverflow.com/questions/17178404/powershell-workflow-exchange-remoting

  • #109160
    Jon

    Participant
    Points: 23
    Rank: Member

    From my own experience with uploading photos to O365, it is a slow painful process.  The joys of dealing with the cloud 😉

  • #109505

    Participant
    Points: 0
    Rank: Member

    After several researchs I discover a better way to handle with the slow exports:

    param
        (
            [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
            [System.Array]
            $users,
     
            [Parameter(Mandatory=$False)]
            [ValidateSet("96x96","240x240","648x648")]
            $Size="240x240",
     
            [Parameter(Mandatory)]
            $Path,
     
            [Parameter(Mandatory)]
            [pscredential]
            [System.Management.Automation.CredentialAttribute()]
            $Credential
        )
     
    process
        {
        foreach($user in $users){
            try
            {
                $Uri = [String]::Concat("https://outlook.office365.com/ews/Exchange.asmx/s/GetUserPhoto?email=",$user.UserPrincipalName,"&size=HR",$Size)
                if(Test-Path -Path $Path)
                {
                    $File = [string]::Concat($Path,"\",$user.sAMAccountName,".jpg")
                    Invoke-WebRequest -Uri $Uri -Credential $Credential -OutFile $File
                }
                else
                {
                    Write-Warning "Please Check the Path"
                }
            }
            catch
            {
                $_.Exception.Message 
            }
        }
    }
    

    $users is an array of a Get-ADUSer invocation and $path is the export location.

    With this code I could decrement the execution time from 3 hours to 8 minutes.

    Reference: http://chen.about-powershell.com/2016/08/import-user-profile-picture-from-exchange-online-using-ews-and-powershell/

    Thank you all for the help and ideas!

You must be logged in to reply to this topic.