Putting the Best Possible Face on Guest Accounts

Several years ago, I wrote about why it’s good to add user photos to Azure AD guest accounts. At that time, Teams was still in its infancy, but it was already clear that Azure B2B Collaboration is an important method to allow external people access to tenant resources. Giving those external people a face by adding photos to their guest accounts makes sense in a world where applications highlight user photos in many ways, such as displaying them in email headers or Teams chats.

Time marches on and the shadow cast by 280-odd million Teams users across the Microsoft 365 landscape is now massive. The passing of time also means that the deprecation of the Azure AD module containing the Set-AzureADUserThumbnailPhoto cmdlet to update user photos will soon be obsolete. It’s time to figure out how to update photos for guest accounts with the Microsoft Graph PowerShell SDK, especially if you’ve migrated a bunch of mail contacts to become guest accounts.

Thumbnails for Guests

Before starting, it’s important to understand that guest accounts only need thumbnail (small) photos. User accounts need higher-definition photos to look well when the photos appear in Teams online meetings (if you’re not using a mesh avatar). As explained in this article, it’s best to use the Exchange Online Set-UserPhoto cmdlet to update user accounts because it uploads higher-quality images to mailboxes than the thumbnails used by Azure AD.

An important part of the preparation is to find suitable photos for guest accounts. You could ask guests for their preferred image or do an internet search to find suitable photos. LinkedIn is my first port of call when I’m looking for someone’s photo. People usually post a nice photo of themselves on LinkedIn that look well even when reduced to a thumbnail. Another advantage of using LinkedIn images is that they’re included in public profiles. In other words, people upload their image so that others can see what they look like. As such, it’s unlikely that you will run into any copyright difficulties when using these images for guest accounts.

It’s easy to copy photos from LinkedIn profiles and save as JPG files using a program like Paint. I save the photos using their original dimensions (many LinkedIn photos are 600 x 600 pixels) and leave it to Azure AD to compress them when it adds thumbnail images to accounts. The largest image I have used is 144 KB; the smallest (a very old LinkedIn picture) is 6 KB.

The script expects the images to be available in a named location. I used c:\UserPhotos\; you can update the script to point it to whatever location you choose to use. What’s important is that the image files are named after the display name of the guest account. For example:

Jack Jones.jpg

Jane Smith.jpg

Folder containing photo thumbnails to update Azure AD guest accounts
Figure 1: Folder containing photo thumbnails to update Azure AD guest accounts

Script Processing

The script goes through these steps

  • Connect to the Microsoft Graph with the User.ReadWrite.All permission (required to update Azure AD accounts).
  • Define the location to find the photos.
  • Define a default photo to use when one is not available for a guest account. I use a simple royalty-free person icon (use an internet search to find your preferred image).
  • Use the Get-MgUser cmdlet to find all guest accounts.
  • Some organizations append the name of the company a guest account works for to the display name. To normalize the display name, the script checks for an opening parenthesis and removes the appended text if found. For instance, the script converts “Tony Redmond (Practical 365)” into “Tony Redmond.” If your organization uses a different method to highlight the companies guests belong to, you’ll need to adjust this code.
  • For each guest account, check if a photo is available in the library. If one is, check if it is newer than the photo currently applied to the account. The script uses a custom attribute to store a timestamp when it applies a photo, so it checks that (if one is available) and the timestamp for the photo to decide if a newer photo is available. If one is, the script updates the account with the Set-MgUserPhotoContent cmdlet
  • If the account never had a photo and a photo is available, the script updates the account.

You can download the script from GitHub. Feel free to suggest improvements.

Speeding Things Up

Fetching all guest accounts to process photos might be a good way to perform an initial population of thumbnails. The script also handles updates when new photos are available for an account. For instance, it will swap out the default image and replace it with a custom image. However, processing all guest accounts every time not the smartest way to proceed unless there are only a few hundred accounts to deal with. Given the popularity of Teams and the use of guest accounts by SharePoint to share documents with external users, the number of guest accounts is likely to grow over time. Organizations might remove some guest accounts through Azure AD access reviews or by writing a PowerShell script to identify inactive guest accounts, but overall, a steady growth in guest numbers can be expected.

To speed things up, we can find which guest accounts need our attention by using the Get-MgPhoto cmdlet to detect if an account has a photo, no photo, or uses the default photo (based on its height and width in pixels). This script does the job and generates arrays of accounts missing photos and those with the default photo.

[array]$Guests = Get-MgUser -Filter "Usertype eq 'Guest'" -All | Sort-Object DisplayName

$GuestsNoPhotos = [System.Collections.Generic.List[Object]]::new() 
[int]$GuestWithPhotos = 0
ForEach ($Guest in $Guests) {
   $Photo = Get-MgUserPhoto -UserId $Guest.Id -ErrorAction SilentlyContinue
   If ($Photo) {
      If ($Photo.Height -eq 150 -and $Photo.Width -eq 150) {
          Write-Host ("Guest account {0} has a default photo" -f $Guest.DisplayName) -foregroundcolor Yellow
          $DataLine  = [PSCustomObject] @{
            Name    = $Guest.DisplayName
            Id      = $Guest.Id
            Photo   = "Default" }
      } Else {
         # Write-Host ("Guest account {0} has a personalized photo" -f $Guest.DisplayName)
   } Else {
      Write-Host ("Guest account {0} has no photo" -f $Guest.DisplayName) -foregroundcolor red
        $DataLine  = [PSCustomObject] @{
          Name    = $Guest.DisplayName
          Id      = $Guest.Id
          Photo   = "Missing" }

[array]$MissingPhotos = $GuestsNoPhotos | Where-Object {$_.Photo -eq "Missing"}
[array]$DefaultPhotos = $GuestsNoPhotos | Where-Object {$_.Photo -eq "Default"}

Write-Host " "
Write-Host ("Total guest accounts                    (0}" -f $Guests.Count)
Write-Host ("Guest accounts with personalized photos {0}" -f $GuestsWithPhotos)
Write-Host ("Guest accounts with the default photo   {0}" -f $DefaultPhotos.Count)
Write-Host ("Guest accounts with missing photos      {0}" -f $MissingPhotos.Count)
Write-Host ""
Write-Host ("Please find photos for these accounts: {0}" -f ($MissingPhotos.Name -join ", "))
Write-Host ("Consider replacing the default photo with a customized image for these accounts: {0}" -f ($DefaultPhotos.Name -join ", "))

To review what guest accounts need attention, you could export the information to a CSV file and use that to track the gathering of photos. When everything’s ready, the script can read in the CSV file and process those accounts instead of having to fetch every guest account and check ones that have a perfectly good photo.

User Accounts Need Photos Too

While it’s good to enhance the appearance of guest accounts with photos, it’s even more critical to have photos for user accounts. Microsoft 365 apps display user photos in profile cards, emails, and other places. The scripts described here are easily adaptable to process photos for user accounts. As mentioned above, the major change is that you should use the Set-UserPhoto cmdlet to upload a higher-quality photo. Unlike the search for photos for guest accounts, it should be much easier to find photos for employees, perhaps even using a feed from the organization’s HR system. At least, that’s the theory.

Cybersecurity Risk Management for Active Directory

Discover how to prevent and recover from AD attacks through these Cybersecurity Risk Management Solutions.

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.

Leave a Reply