User Profile Photo Sync to SharePoint
Periodically sync Office 365 user profile photos to a SharePoint image library for use in custom apps and directories.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
A scheduled cloud flow that periodically pulls every Office 365 user's profile photo and uploads it to a central SharePoint document library. The library becomes the single, predictable source of user photos for custom apps, Power Pages directories, intranet people pickers, and any other surface that needs portrait images without hitting Microsoft Graph at runtime.
Use Case
Custom apps and Power Pages sites that need to render user photos run into the same wall: the Office 365 Users connector's UserPhoto action requires the calling user's permission to read every target user, and Microsoft Graph rate-limits photo endpoints aggressively when a popular surface fans out to many users. Caching photos in a SharePoint image library breaks both constraints — the app now reads files from a familiar SharePoint library, the flow handles the Graph traffic on a schedule, and IT controls refresh cadence by tweaking the recurrence trigger.
Typical consumers: a Power Apps employee directory, a SharePoint org chart web part backed by REST, a Power Pages staff profile site, and any HR onboarding flow that needs a headshot reference.
The flow is ideal for teams that:
- Power Apps employee directories that render user photos without hitting Graph at runtime
- SharePoint org chart web parts backed by REST that key off a predictable image library
- Power Pages staff profile sites needing cached portraits for anonymous visitors
- HR onboarding flows that need a stable headshot reference per user
- IT teams that want to control photo refresh cadence and avoid Graph throttling on popular surfaces
Flow Architecture
Recurrence Daily 8AM
RecurrenceRuns once per day at 08:00 UTC to drive the daily photo sync.
Init varSharePointSiteUrl
Initialize variable (string)Reads the `flowlibs_SharePointSiteURL` environment variable so the destination site is configurable per tenant.
Init varLibraryName
Initialize variable (string)Reads the `flowlibs_UserPhotoLibraryName` environment variable for the destination library display name.
Init varSearchFilter
Initialize variable (string)Reads the `flowlibs_UserSearchFilter` environment variable. Empty value means all users.
Init varNotificationRecipient
Initialize variable (string)Reads the `flowlibs_NotificationRecipient` environment variable for the summary email recipient.
Init varFolderPath
Initialize variable (string)Computes the server-relative folder path from the library name, handling SharePoint's hyphen-to-double-space path quirk.
Init varSyncedCount
Initialize variable (integer)Counter for successfully synced photos, starts at 0.
Init varErrorCount
Initialize variable (integer)Counter for per-user sync errors, starts at 0.
Search For Users
Office 365 Users — SearchUserV2Returns up to 100 enabled users matching the optional search term from `varSearchFilter`.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_SharePointSiteURL | String | https://your-tenant.sharepoint.com | Root SharePoint site URL that hosts the destination photo library. Set to your tenant's site URL. |
| flowlibs_UserPhotoLibraryName | String | FlowLibs - User Profile Photos | Display name of the destination document library where user photos are uploaded. |
| flowlibs_UserSearchFilter | String | <configure> | Optional search term passed to `SearchUserV2`. Leave empty to sync all users (up to 100), or set to a department name, surname prefix, or domain fragment to scope the run. |
| flowlibs_NotificationRecipient | String | you@yourcompany.com | Email address that receives the daily sync summary. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Office 365 Users | shared_office365users | SearchUserV2 (Returns up to 100 enabled users matching the search filter) UserPhoto_V2 (Downloads the binary profile photo for the current user via `/v1.0/users/{id}/photo/$value`) |
| SharePoint Online | shared_sharepointonline | CreateFile (Uploads the binary photo as `{userPrincipalName}.jpg` into the destination library) |
| Office 365 Outlook | shared_office365 | SendEmailV2 (Sends the daily HTML summary email to the configured recipient) |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Change the schedule
- Edit the Recurrence_Daily_8AM trigger. For weekly off-hours runs, set frequency: "Week", interval: 1, and pick a weekDays value plus an hours value that fits your maintenance window. For more frequent refresh during a migration, switch to frequency: "Hour" with interval: 4 — but expect Graph throttling above ~1 photo/sec sustained.
- Scope which users sync
- Update the flowlibs_UserSearchFilter env var. SearchUserV2 accepts a single search term that matches against display name, mail, and userPrincipalName. To scope by department, surname, or office, set this to the value you want to match (for example Sales or Smith). For an everyone sync, leave it empty — the flow already passes isSearchTermRequired: false. To go beyond 100 users, add a paging loop using the skipToken query param of SearchUserV2.
- Change the destination library
- Update flowlibs_UserPhotoLibraryName. The Init_varFolderPath action automatically converts the library display name into the server-relative path SharePoint actually uses (replacing - with to match SharePoint's path-encoding behavior). If you point at a library on a different site, also update flowlibs_SharePointSiteURL.
- Change the file naming convention
- The Upload_Photo_To_SharePoint
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Server-relative folder path from library name
Used in `Init_varFolderPath`. Converts the SharePoint library display name into its server-relative path. SharePoint silently turns ` - ` (space-hyphen-space) in a library title into ` ` (double space) on disk; this expression mirrors that transformation so the flow stays portable across libraries.
EXPR.02Current user object id
Used in the `id` parameter of `Get_User_Photo`. Object id (GUID) of the current user, required by the `/v1.0/users/{id}/photo/$value` Graph route that `UserPhoto_V2` wraps.
EXPR.03UPN-based photo filename
Used in the `name` parameter of `Upload_Photo_To_SharePoint`. UPN-based filename keeps photos human-readable and trivially joinable to user records downstream.
EXPR.04Raw photo binary passthrough
Used in the `body` parameter of `Upload_Photo_To_SharePoint`. Passes the raw photo binary returned by `UserPhoto_V2` straight into `CreateFile` without intermediate base64 conversion.
EXPR.05Resilient user count for summary email
Used in the summary email body. `coalesce` falls back to an empty array if the search returned no users so the email never errors on a null length.
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.