Simple script to upload user photos to a SharePoint Online library. The photos are pulled from active directory in a separate script.
###
# Upload User Photos to SharePoint Online Library
###
# This script is designed to upload user photos to a SharePoint Online library. It first removes existing photos from the specified library and then uploads new photos from a local directory. The script uses the PnP PowerShell module to interact with SharePoint Online and includes logging and error handling to ensure a smooth execution.
###
# Before running the script, make sure to:
# 1. Install the PnP PowerShell module if you haven't already: Install-Module -Name PnP.PowerShell
# 2. Set up an Azure AD app registration with certificate-based authentication and grant it the necessary permissions to access SharePoint Online.
###
# Note: Be cautious when running scripts that delete content. Always test in a non-production environment first and ensure you have backups if needed.
###
# The script is structured in the following phases:
# 1. Configuration: Set up parameters for sleep intervals, retry logic, and connection settings.
# 2. Connect to SharePoint Online using the specified credentials.
# 3. Remove existing photos from the target library in batches to optimize performance.
# 4. Upload new photos from the local directory, with error handling and logging for each upload.
# 5. Final output of the total number of photos uploaded and completion of the transcript.
###
# Make sure to replace the placeholder values for ClientID, ThumbPrint, Tenant, SiteURL, and DestinationPath with your actual configuration before running the script.
###
Start-Transcript -Path "C:\Temp\UserPhotos\0C - Transscript.txt"
# -----------------------------
# Configuration
# -----------------------------
$DeleteSleepSeconds = 0 # pause between deletes (0 = no pause)
$BetweenPhasesSleepSeconds = 15 # pause between delete and upload phases
# -----------------------------
# Connection settings
# -----------------------------
$ClientID = "00000000-0000-0000-0000-000000000000" # Replace with your Azure AD app registration's client ID
$ThumbPrint = "" # Replace with your certificate thumbprint
$Tenant = "contoso.onmicrosoft.com" # Replace with your tenant domain
$SiteURL = "https://contoso.sharepoint.com/sites/YourSite" # Replace with your SharePoint site URL
$DestinationPath = "Employee Photos" # Site-relative library/folder path
# Connect to SharePoint Online using Certificate
Connect-PnPOnline -Url $SiteURL -ClientId $ClientID -Thumbprint $ThumbPrint -Tenant $Tenant
# Location of exported photos (files only, excluding scripts and logs)
$newUserPhotos = Get-ChildItem -Path "C:\Temp\UserPhotos\" -Exclude *.txt, *.ps1
$newUserPhotos = $newUserPhotos | Sort-Object
Write-Host "Found $($newUserPhotos.Count) photos on disk"
# -----------------------------
# Remove existing photos
# -----------------------------
try {
Write-Host ""
Write-Host "Removing photos from SP"
$oldUserPhotos = Get-PnPListItem -List $DestinationPath -PageSize 1000
$totalOld = $oldUserPhotos.Count
$oldUserPhotoCount = 0
if ($totalOld -gt 0) {
# Batch deletes to reduce round trips
$batch = New-PnPBatch
foreach ($oldUserPhoto in $oldUserPhotos) {
$oldUserPhotoCount++
Write-Host "Removing old image $oldUserPhotoCount of $totalOld"
#Remove-PnPListItem -List $DestinationPath -Identity $oldUserPhoto -Batch $batch -Force
Remove-PnPListItem `
-List $DestinationPath `
-Identity $oldUserPhoto.Id `
-Batch $batch
if ($DeleteSleepSeconds -gt 0) {
Start-Sleep -Seconds $DeleteSleepSeconds
}
}
Invoke-PnPBatch -Batch $batch
}
}
catch {
Write-Host $_.Exception.Message
Write-Host "---"
}
finally {
Write-Host "---"
if ($BetweenPhasesSleepSeconds -gt 0) {
Start-Sleep -Seconds $BetweenPhasesSleepSeconds
}
}
# -----------------------------
# Upload latest photos
# -----------------------------
$totalNew = $newUserPhotos.Count
$newUserPhotoCount = 0
foreach ($newUserPhoto in $newUserPhotos) {
$newUserPhotoCount++
Write-Host "Uploading new image $newUserPhotoCount of $totalNew"
$newUserPhotoPath = $newUserPhoto.FullName
$newUserPhotoFileName = $newUserPhoto.BaseName.Replace('.', ' ') + $newUserPhoto.Extension
$newUserPhotoTitle = $newUserPhoto.BaseName.Replace('.', ' ')
try {
$uploaded = Add-PnPFile `
-Path $newUserPhotoPath `
-Folder $DestinationPath `
-NewFileName $newUserPhotoFileName `
-Values @{ "Title" = $newUserPhotoTitle } `
-Verbose `
-ErrorAction Stop
Write-Host "Uploaded $newUserPhotoFileName to $($uploaded.ServerRelativeUrl)"
}
catch {
Write-Host "Upload error for $newUserPhotoPath"
Write-Host $_.Exception.ToString()
throw
}
}
# -----------------------------
# Final output
# -----------------------------
Write-Host ""
Write-Host "---"
Write-Host "Uploaded a total of $($newUserPhotos.Count) photos"
Write-Host "---"
Stop-Transcript
