Turn any Windows computer into an automatic digital photo frame that displays family photos throughout the day. Perfect for elderly relatives who want to see family memories without touching anything.
A slideshow that automatically starts at 10:30 AM, runs for 20 minutes, then repeats every hour until 6:30 PM. You can easily change these times to suit your needs.
Time required: 15-20 minutes
Research shows that viewing family photos can improve mood, reduce loneliness, and help with memory recall in older adults.
Once set up, the slideshow runs on its own. Your loved one doesn't need to touch anything or remember how to start it.
Digital photo frames cost £50-200. If you already have a spare computer or monitor for Family Hub, this solution is completely free.
The slideshow runs at predictable times throughout the day, creating a pleasant routine and keeping them connected to family.
First, create a folder and add your family photos.
C:\Slideshow\C:\Slideshow\ folderWant a photo to play a voice message? Save an audio file (MP3 or WAV) with the exact same name as the photo.
Example:
C:\Slideshow\Birthday2025.jpgC:\Slideshow\Birthday2025.mp3When the photo appears, the audio will play automatically. The slideshow will wait for the audio to finish before moving to the next photo.
We'll create three PowerShell scripts that control the slideshow.
PowerShell scripts are simple text files that tell Windows what to do. They're safe and easy to create – just copy and paste the code below.
C:\SlideshowScripts\ and save all three script files there.
This script starts the slideshow and displays your photos fullscreen.
Start-Slideshow.ps1C:\SlideshowScripts\$folder = "C:\SlideshowPhotos20260221" and change it to $folder = "C:\Slideshow" (or whatever folder path you created in Step 1).
# Path to your slideshow folder
$folder = "C:\SlideshowPhotos20260221"
# Load necessary assemblies for GUI and Audio
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName PresentationCore
# Initialize Audio Player
$mediaPlayer = New-Object System.Windows.Media.MediaPlayer
# Set volume (0.0 to 1.0)
$mediaPlayer.Volume = 0.8
# Get all images and shuffle them randomly
Write-Host "Loading images from $folder..."
$images = Get-ChildItem -Path $folder -Filter "*.jpg" | Sort-Object { Get-Random }
$imageQueue = new-object System.Collections.Queue
$images | ForEach-Object { $imageQueue.Enqueue($_.FullName) }
if ($imageQueue.Count -eq 0) {
Write-Host "No images found in $folder"
Read-Host "Press Enter to exit"
exit
}
# Create the fullscreen form
$form = New-Object System.Windows.Forms.Form
$form.Text = "Random Slideshow"
$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None
$form.WindowState = [System.Windows.Forms.FormWindowState]::Maximized
$form.BackColor = [System.Drawing.Color]::Black
$form.TopMost = $true
# PictureBox to display images
$pictureBox = New-Object System.Windows.Forms.PictureBox
$pictureBox.Dock = [System.Windows.Forms.DockStyle]::Fill
$pictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom
$form.Controls.Add($pictureBox)
# Function to load next image
$script:currentImage = $null
# Define Timer first so function can use it
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 10000
function Show-NextImage {
$timer.Stop() # Stop timer while loading/playing
if ($imageQueue.Count -eq 0) {
# Reshuffle if empty
$shuffled = $images | Sort-Object { Get-Random }
foreach ($img in $shuffled) { $imageQueue.Enqueue($img.FullName) }
}
if ($imageQueue.Count -gt 0) {
$nextFile = $imageQueue.Dequeue()
# Dispose previous image to free memory
if ($pictureBox.Image) {
$oldImage = $pictureBox.Image
$pictureBox.Image = $null
$oldImage.Dispose()
}
try {
# Load new image
if (Test-Path $nextFile) {
# 1. Update Image
$pictureBox.Image = [System.Drawing.Image]::FromFile($nextFile)
# 2. Check for Audio
$basePath = $nextFile.Substring(0, $nextFile.LastIndexOf('.'))
$audioFile = $null
if (Test-Path "$basePath.mp3") { $audioFile = "$basePath.mp3" }
elseif (Test-Path "$basePath.wav") { $audioFile = "$basePath.wav" }
# 3. Handle Audio/Timer Logic
$mediaPlayer.Stop()
if ($audioFile) {
try {
$mediaPlayer.Open(([Uri]$audioFile))
$mediaPlayer.Play()
# We don't know duration yet (async).
# Strategy: Start the standard 10s timer.
# BUT, also hook into MediaEnded to ensure we don't cut it off if it's long.
# Actually, simpler: If audio exists, disable timer, wait for MediaEnded.
# If audio is short, we might advance too fast?
# User only asked about "longer". Implicitly keeping 10s minimum is good UI.
# Let's use a flag to track if we are waiting for audio
$script:waitingForAudio = $true
$timer.Start()
} catch {
Write-Host "Audio Error: $_"
$timer.Start()
}
} else {
$script:waitingForAudio = $false
$timer.Start()
}
}
}
catch {
Write-Host "Error loading $nextFile"
$timer.Start()
}
}
}
# Timer Tick Logic
$timer.Add_Tick({
# If audio is playing, check if it's done or if we should keep waiting
if ($script:waitingForAudio) {
# Check position vs duration if possible, or just rely on events.
# MediaPlayer doesn't easily expose "IsPlaying".
# But we can check Position.
if ($mediaPlayer.NaturalDuration.HasTimeSpan) {
if ($mediaPlayer.Position -lt $mediaPlayer.NaturalDuration.TimeSpan) {
# Audio still playing and valid, skip this tick
return
}
}
}
Show-NextImage
})
# Initial image
Show-NextImage
# Exit on Escape key or Click
$form.KeyPreview = $true
$form.Add_KeyDown({
if ($_.KeyCode -eq [System.Windows.Forms.Keys]::Escape) {
$mediaPlayer.Stop()
$timer.Stop()
$form.Close()
}
})
$pictureBox.Add_Click({
$mediaPlayer.Stop()
$timer.Stop()
$form.Close()
})
# Show the slideshow
Write-Host "Starting slideshow. Press ESC or click the image to exit."
[void]$form.ShowDialog()
# Cleanup
$mediaPlayer.Close()
# Cleanup
if ($pictureBox.Image) { $pictureBox.Image.Dispose() }
$form.Dispose()
What this script does:
This script automatically stops the slideshow after the scheduled time.
Stop-Slideshow.ps1C:\SlideshowScripts\
# Close Microsoft Photos
Get-Process "Microsoft.Photos" -ErrorAction SilentlyContinue | Stop-Process
# Close Custom PowerShell Slideshow
Get-Process | Where-Object { $_.MainWindowTitle -eq "Random Slideshow" } | Stop-Process -Force
What this script does:
This script creates the automatic schedule in Windows Task Scheduler.
Set-Slideshow-Schedule.ps1C:\SlideshowScripts\
# Set-Slideshow-Schedule.ps1
# Creates Scheduled Tasks to run the slideshow periodically and wake the computer.
# Get the target username
$targetUser = Read-Host "Enter the username to run the slideshow for (e.g. Sadat)"
if ([string]::IsNullOrWhiteSpace($targetUser)) {
Write-Error "Username cannot be empty."
exit
}
# --- Configuration ---
$scriptsFolder = $PSScriptRoot
$startScript = Join-Path $scriptsFolder "Start-Slideshow.ps1"
$stopScript = Join-Path $scriptsFolder "Stop-Slideshow.ps1"
$taskNameStart = "RandomSlideshow_Start"
$taskNameStop = "RandomSlideshow_Stop"
# Schedule: 10:30 Start, repeats every hour until 18:30.
# Stop script runs 20 minutes after every start (10:50, 11:50, etc).
# --- Validation ---
if (-not (Test-Path $startScript)) { Write-Error "Start script not found: $startScript"; exit }
if (-not (Test-Path $stopScript)) { Write-Error "Stop script not found: $stopScript"; exit }
# --- Clean up existing tasks ---
Write-Host "Removing existing tasks..."
Unregister-ScheduledTask -TaskName $taskNameStart -Confirm:$false -ErrorAction SilentlyContinue
Unregister-ScheduledTask -TaskName $taskNameStop -Confirm:$false -ErrorAction SilentlyContinue
# --- Create Start Task ---
# Trigger: Daily at 10:30, repeat every 1 hour, for 8 hours (ends at 18:30 run)
$startTrigger = New-ScheduledTaskTrigger -Daily -At "10:30 AM"
$startTrigger.Repetition.Interval = New-TimeSpan -Hours 1
$startTrigger.Repetition.Duration = New-TimeSpan -Hours 8
# Action: Run PowerShell with the Start script (WindowStyle Hidden to avoid popup, but script itself creates a form)
# We use -ExecutionPolicy Bypass to ensure it runs
$startAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File `"$startScript`""
# Settings: Run only when user is logged on
# Removing -WakeToRun as it may require higher privileges
$startSettings = New-ScheduledTaskSettingsSet -Priority 1 -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
Write-Host "Registering Start Task: $taskNameStart"
# Use -Force to overwrite if exists, but we already tried to unregister.
Register-ScheduledTask -TaskName $taskNameStart -Action $startAction -Trigger $startTrigger -Settings $startSettings -Description "Starts the random slideshow at 10:30 and hourly until 18:30" -User $targetUser -Force
# --- Create Stop Task ---
# Trigger: Daily at 10:50 (20 mins after start), repeat every 1 hour, for 8 hours
$stopTrigger = New-ScheduledTaskTrigger -Daily -At "10:50 AM"
$stopTrigger.Repetition.Interval = New-TimeSpan -Hours 1
$stopTrigger.Repetition.Duration = New-TimeSpan -Hours 8
$stopAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File `"$stopScript`""
$stopSettings = New-ScheduledTaskSettingsSet -Priority 1
Write-Host "Registering Stop Task: $taskNameStop"
Register-ScheduledTask -TaskName $taskNameStop -Action $stopAction -Trigger $stopTrigger -Settings $stopSettings -Description "Stops the random slideshow 20 minutes after start" -User $targetUser -Force
Write-Host "Done! Tasks scheduled."
Write-Host "Start Task: 10:30 daily, repeats hourly until 18:30"
Write-Host "Stop Task: 10:50 daily, repeats hourly until 18:50"
pause
What this script does:
Now we'll run the script to create the automatic schedule.
Screenshot reference: Run Powershell as Administrator
Watch a video tutorial: How to open PowerShell as Administrator
In the PowerShell window, type this command and press Enter:
cd C:\SlideshowScripts
This moves PowerShell into the folder where your scripts are saved.
Windows blocks scripts by default for security. We need to allow them. Type this command and press Enter:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Press Y and then Enter when asked to confirm.
Now type this command and press Enter:
.\Set-Slideshow-Schedule.ps1
whoami in PowerShell and press Enter. It will show something like "COMPUTERNAME\YourUsername" – use the part after the backslash.
Before waiting for the scheduled time, let's test that everything works.
C:\SlideshowScripts\Screenshot reference: [Insert screenshot of Task Scheduler showing the two slideshow tasks]
Want to change when the slideshow runs or how long it lasts? Here's how.
Open Set-Slideshow-Schedule.ps1 in Notepad and find these lines:
Find line 34:
$startTrigger = New-ScheduledTaskTrigger -Daily -At "10:30 AM"
Change "10:30 AM" to your preferred time, like "08:00 AM" or "09:15 AM"
Find line 35:
$startTrigger.Repetition = New-ScheduledTaskTrigger -Once -At "10:30 AM" -RepetitionInterval (New-TimeSpan -Hours 1) -RepetitionDuration (New-TimeSpan -Hours 8)
Change -Hours 1 to -Hours 2 for every 2 hours, or -Minutes 30 for every 30 minutes
Same line 35: Change -RepetitionDuration (New-TimeSpan -Hours 8)
If you start at 8:00 AM and want to end at 8:00 PM, that's 12 hours, so use -Hours 12
Find line 52:
$stopTrigger = New-ScheduledTaskTrigger -Daily -At "10:50 AM"
The stop time is 20 minutes after start (10:30 + 20 = 10:50). Change this to your preferred duration.
Also update line 53 to match:
$stopTrigger.Repetition = New-ScheduledTaskTrigger -Once -At "10:50 AM" ...
.\Set-Slideshow-Schedule.ps1
Open Start-Slideshow.ps1 in Notepad and find line 43:
$timer.Interval = 10000
This is in milliseconds (1000 = 1 second). The current value of 10000 means 10 seconds per photo.
$timer.Interval = 5000$timer.Interval = 15000$timer.Interval = 30000Save the file after making changes. The new timing will apply the next time the slideshow runs.
Your slideshow will automatically include any new photos you add to the folder.
C:\Slideshow\C:\Slideshow\If you set up remote access (TeamViewer, AnyDesk, Windows Remote Desktop), you can add and remove photos from anywhere, making it easy to keep the slideshow fresh with new family pictures.
Common issues and how to fix them.
Set-ExecutionPolicy RemoteSigned -Scope CurrentUserCan you do this on older systems or tablets?
Good news: These exact scripts work on Windows 10 as well! The process is identical:
Android doesn't use PowerShell or Task Scheduler, so you'll need a different approach.
Download a dedicated app from the Google Play Store:
Tasker is an automation app (paid, about £3) that can schedule apps to open and close:
Tasker has a learning curve, but guides are available on YouTube: Search: "Tasker schedule app Android"
Amazon Fire tablets have a built-in "Show" mode that turns them into smart displays:
| Feature | Windows (10/11) | Android |
|---|---|---|
| Setup Complexity | Medium (scripts required) | Easy (apps available) |
| Scheduling | Fully customizable | Depends on app |
| Audio Support | Yes (built-in) | Some apps support it |
| Cost | Free (if you have PC) | Free - £3 for apps |
| Screen Size | Any monitor size | Tablet size (7-12") |
| Power Usage | Higher | Lower |
| Remote Updates | Yes (Remote Desktop) | Yes (cloud sync) |
Videos, guides, and links to help you succeed.
If you run into problems or have questions about setting up your slideshow, we're here to help.
Or visit our FAQ page for more Family Hub information.