Saving the (disappearing) Windows 10 Lock Screen Images

PowerShell Apr 29, 2020

Window 10 lock screen images come and go - driven by Microsoft.  They are always unique and typically you wish you could save them for future background images.

Well its possible.

Windows 10 lock screen image files are uniquely named (without a file type) and are created and saved (albeit temporarily) in the following folder:

Under "C:\Users<your username>" got to the following folder:

Typically the files you are interested in are greater than 250Kb in size, and under the hood are normal jpg files.

What we want is to regularly copy them when they appear and save them into a different folder where can then use them as background images.

The following PowerShell script does all of this and so by scheduling the script to run every hour in the background on your machine, you can be sure to start to build up a library of background images from the lock screen collection of Microsoft.

NB: While this works its almost certainly not efficient code!

NB: You will almost certainly need to change the script execution policy on your machine.  Be warned!!  Understand the risks of doing this before you continue!


Set-ExecutionPolicy RemoteSigned

The script is as follows:

# Copy Windows 10 Lock Screen images to destination folder and
# sort them into portrait and landscape versions
# these can then be used as slideshow background images.

# Ad a Scheduled task in Windows.  Add the Action line as:
# Start a Program: powershell.exe
# With parameters: -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass <location of this script>
# e.g. -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass C:\Users\tucke\Documents\Scripts\getbackgroundimages.ps1
# Params:	-WindowStyle Hidden:  While this wont ABSOLUTELY hide the Powershell window popup, its only shown very very quickly
# 			-ExecutionPolicy Bypass: Start a PowerShell session that allows for running scripts and keeps the lowered permissions isolated to just the current running process
# Requirements:
# A folder where you will store these background images
# That folder must have two subfolders: "portrait" and "landscape"

#This function is adapted from Scripting Guy:

#Set-ExecutionPolicy RemoteSigned 

# Define Parameters for this script
# The user personal account folder name under c:\Users
# $script:username = "tucke"
# The Windows lock file image folder. Multiple images are downloaded almost daily at random times when you are online.
# $script:source = "C:\Users\$script:username\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets\"
# The destination folder where you will hold your "portrait" and "landscape" folders to hold the sorted background images
# $script:destination = "C:\Users\$script:username\OneDrive\Desktop\pix\"

$script:username = "tucke"
#$script:source = "C:\Users\$script:username\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets\"
$script:source = "C:\jpg\"
$script:destination = "C:\Users\$script:username\OneDrive\Desktop\pix\"

# [string[]]$Excludes = @('landscape', 'portrait') - not used

# This is the filesize limit I have found worked. Otherwise you get icon images...and not background images
$filesize = 250KB

# Remove any leftover *.jpg files in $destination folder in case of script breaks.  Otherwise you get double.jpg.jpg files
Remove-Item $destination\*.jpg -Force

# [long version] Get-ChildItem $source | where { $_.Length -gt $filesize} | Copy-Item -Destination $destination -force
# Get current stack of background images and copy then to target pix folder.  I found these to almost always be large than 250kb
gci $source | where { $_.Length -gt $filesize} | Copy-Item -Destination $destination -force

#[long version] Get-ChildItem $destination -Filter “*.” -Exclude $Excludes  | Rename-Item -NewName {$ + ’.jpg’ }
# Get the copied files, and add the .jpg file extension
gci $destination -Filter “*.” | where { ! $_.PSIsContainer } | Rename-Item -NewName {$ + ’.jpg’ }

function GetImage() {

param([string]$folder = $script:destination)

    function funLine($strIN) 
     $strLine = "=" * $strIn.length
     write-Host -ForegroundColor Yellow "`n$strIN"
     Write-Host -ForegroundColor Cyan $strLine
    } #end funline

    foreach($sFolder in $folder)
        $a = 0
        $objShell = New-Object -ComObject Shell.Application
        $objFolder = $objShell.namespace($sFolder)
        $isjpg = 0
        foreach ($strFileName in $objFolder.items())
        { #FunLine( "$($")
            for ($a ; $a  -le 266; $a++)
            if($objFolder.getDetailsOf($strFileName, $a))
                $hash += @{ `
                        $($objFolder.getDetailsOf($objFolder.items, $a))  =`
                        $($objFolder.getDetailsOf($strFileName, $a)) 
                        } #end hash
                $itemtype = $hash["Item Type"]
                #if (1 -eq 2) {
                if ($itemtype -eq "JPG File" -Or $isjpg -eq 1) {
                    $isjpg = 1
                    $width = $hash["Width"]
                    $height = $hash["Height"]
                    $path = $hash["Path"] #essentially same as $destination
                    $file = $hash["Filename"]
                    $imgtype = $hash["Type"]
                    if ($width.length -gt 0) {
                        $wid = $width.substring(0,5)
                    if ($height.length -gt 0) {
                        $hig = $height.substring(0,5)
                    if ($path.length -gt 0) {
                        $pathname = $path
                    if ($file.length -gt 0) {
                        $portrait = gci $destination -Filter “$file.jpg” | where { ! $_.PSIsContainer }
                        $portrait = $script:destination +"landscape\" + $portrait
                        $landscape = gci $destination -Filter “$file.jpg” | where { ! $_.PSIsContainer }
                        $landscape = $script:destination + "portrait\" + $landscape

                    if ($imgtype -eq "JPG File") {
                        if ($wid -gt $hig) {
                            FunLine( "$($portrait)")
                            Copy-Item -Path $pathname -Destination $portrait -Force
                        } else {
                            FunLine( "$($landscape)")
                            Copy-Item -Path $pathname -Destination $landscape -Force
                        $isjpg = 0
                        $imgtype = ""
                }  else { #end Type = JPG File
                    $isjpg = 0
                    $imgtype = ""
                } #end if
            } #end for 
        } #end foreach $filename
    } #end foreach $folder

# Process images and split them into portrait or landscape
GetImage -folder $destination
# Cleanup
Remove-Item $destination\*.jpg -Force