Tom's Homepage

2026-06-02: Bing Wallpaper Automatic Update Script


(This article is also available via the short link tomrei.ch/bingwallpaper)

Windows advertises the ability to automatically use the daily Bing image as your desktop wallpaper, but in practice I find it hit or miss — especially across multiple machines. Sometimes it updates, sometimes it doesn't, and sometimes it just quietly stops working. So I worked with GitHub Copilot to put together a small PowerShell script that does the job reliably, paired with a Scheduled Task that kicks it off when I unlock the machine.

The script fetches today's Bing image metadata, downloads the UHD version (falling back to the standard version if UHD isn't available), keeps the last 7 wallpapers around, logs what it's doing, and then sets the wallpaper via the Win32 API. It also skips itself entirely when running inside a Remote Desktop session so it doesn't fight with the remote desktop's wallpaper handling.

The script

Save this as C:\Scripts\BingWallpaper.ps1:

# ================================
# Bing Wallpaper Fetcher (No App)
# Keeps last 7 wallpapers + Logging
# ================================

# Where to save the wallpaper
$wallpaperDir = "$env:LOCALAPPDATA\BingWallpapers"
if (!(Test-Path $wallpaperDir)) { New-Item -ItemType Directory -Path $wallpaperDir | Out-Null }

# Log file
$logFile = Join-Path $wallpaperDir "BingWallpaper.log"

function Log($msg) {
    $timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
    Add-Content -Path $logFile -Value "$timestamp  $msg"
}

Log "----- Script start -----"

# Skip if running inside a Remote Desktop session
if ($env:SESSIONNAME -and $env:SESSIONNAME -like "RDP-*") {
    Log "Remote Desktop session detected ($env:SESSIONNAME). No action taken."
    exit 0
}

# Bing API endpoint (today's image)
$bingApi = "https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US"

# Fetch metadata
try {
    $response = Invoke-RestMethod -Uri $bingApi -UseBasicParsing
} catch {
    Log "ERROR: Failed to fetch Bing metadata: $_"
    exit 1
}

$image = $response.images[0]

# Build URLs
$baseUrl = "https://www.bing.com"
$uhdUrl  = $baseUrl + $image.urlbase + "_UHD.jpg"
$fullUrl = $baseUrl + $image.url

# Determine output filename
$filename = "BingWallpaper_$($image.startdate).jpg"
$filepath = Join-Path $wallpaperDir $filename

# If today's wallpaper already exists, exit early
if (Test-Path $filepath) {
    Log "Already on latest wallpaper ($filename). No action taken."
    exit 0
}

# Try UHD first, fall back if unavailable
try {
    Invoke-WebRequest -Uri $uhdUrl -Method Head -TimeoutSec 5 -UseBasicParsing | Out-Null
    $downloadUrl = $uhdUrl
    Log "UHD available. Using UHD URL."
} catch {
    $downloadUrl = $fullUrl
    Log "UHD unavailable. Using fallback URL."
}

# Download the wallpaper
try {
    Invoke-WebRequest -Uri $downloadUrl -OutFile $filepath -UseBasicParsing
    Log "Downloaded new wallpaper: $filename"
} catch {
    Log "ERROR: Failed to download wallpaper: $_"
    exit 1
}

# Cleanup: keep only the 7 most recent wallpapers
$files = Get-ChildItem -Path $wallpaperDir -Filter "BingWallpaper_*.jpg" |
         Sort-Object LastWriteTime -Descending

if ($files.Count -gt 7) {
    $filesToDelete = $files | Select-Object -Skip 7
    foreach ($f in $filesToDelete) {
        Remove-Item $f.FullName -Force
        Log "Deleted old wallpaper: $($f.Name)"
    }
}

# Set wallpaper (registry + broadcast)
$code = @"
using System;
using System.Runtime.InteropServices;

public class Wallpaper {
    [DllImport("user32.dll", SetLastError = true)]
    public static extern bool SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
}
"@

Add-Type $code

Set-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name wallpaper -Value $filepath
[Wallpaper]::SystemParametersInfo(20, 0, $filepath, 3) | Out-Null

Log "Wallpaper applied successfully."
Log "----- Script end -----"

The VBScript launcher

The Scheduled Task launches a small VBScript wrapper instead of PowerShell directly. This is what keeps the PowerShell window from briefly flashing on screen every time it runs. Save this as C:\Scripts\BingWallpaper.vbs:

Set objShell = CreateObject("Wscript.Shell")
objShell.Run "powershell.exe -NoProfile -ExecutionPolicy Bypass -File ""C:\Scripts\BingWallpaper.ps1""", 0, False

Setting it up

  1. Create the folder C:\Scripts if it doesn't already exist.
  2. Save the PowerShell script above as C:\Scripts\BingWallpaper.ps1.
  3. Save the VBScript above as C:\Scripts\BingWallpaper.vbs.
  4. Open Task Scheduler and create a new task (not a basic task).
  5. On the General tab, give it a name like "Bing Wallpaper Updater" and make sure it runs as the currently logged-in user (the default). Do not check "Run whether user is logged on or not" — the script needs to update the current user's desktop.
  6. On the Triggers tab, add a new trigger. Set "Begin the task" to On workstation unlock for any user (or your specific user). You can optionally add a second trigger at logon if you'd like it to run then as well.
  7. On the Actions tab, add a new action with:
    • Action: Start a program
    • Program/script: wscript.exe
    • Add arguments: "C:\Scripts\BingWallpaper.vbs"
  8. On the Conditions tab, uncheck "Start the task only if the computer is on AC power" if you want it to run on battery too.
  9. Save the task and unlock your machine to test it.

Logs (and the cached wallpapers) end up in %LOCALAPPDATA%\BingWallpapers, which is handy if you ever need to see why it didn't pick up today's image.

© 2026 Tom Reich

Home