'Batch file to change desktop background only works sporadically or after spam opening batch. I would like help making it change immediately

@ECHO on

CD C:\Users\User

reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v Wallpaper /t REG_SZ /d C:\Users\User\Desktop\folder\Background1.png /f

reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v TileWallpaper /t REG_SZ /d 0 /f

RUNDLL32.EXE USER32.DLL, UpdatePerUserSystemParameters 1 True

pause

The User and Folder names have been defaulted for readability



Solution 1:[1]

The wallpaper change can be done immediately using a batch powershell hybrid that uses SystemParametersInfo() to update the desktop wallpaper.

Known to support: .Jpg .Bmp and .Png

The below is scripted for use with images in th default %Userprofile%\pictures folder - modify to suit your needs.

Powershell function source

A newer function that supports an argument for style can be found at the above link

More reading

<# : batch portion
:# The above line marks the beginning of a powershell comment block; and the Batch component of the Script. Do not modify.
::# Author: T3RRY ; Creation Date 12/02/2021 ; Version: 1.0.3
::# * Batch Powershell Hybrid * Resource: https://www.dostips.com/forum/viewtopic.php?f=3&t=5543
::# Script Purpose:
::# - Change the wallpaper from command prompt through the use of Parameter; Or by Input if no Parameter.
::# - Script Designed for use with pictures in the %Userprofile%\Pictures Directory
::#   or sub directories and should be placed in the %Userprofile%\Pictures Directory.
::#   - Hot tip: Add the %Userprofile%\Pictures Directory to your System environment Path variable.
::#     https://helpdeskgeek.com/windows-10/add-windows-path-environment-variable/

@Echo off & Mode 120,40

:# Test for Arg 1 ; Usage output ; Offer Input or Abort

 Set "Arg1=%~1"
 If "%Arg1%" == "" (
  Call "%~f0" "/?"
  Echo/
  Set "Wallpaper="
  Set /P "Wallpaper=Press ENTER to abort, or enter filepath / Search Term: "
  Setlocal EnableDelayedExpansion
  If "!Wallpaper!" == "" Exit /B
  Call "%~f0" "!Wallpaper!"
  Endlocal
  Exit /B
 )

:# Test for Unsupported Arg Count ; Notify Ignored Args; Show Help; Offer Abort

 Set ParamErr=%*
 If Not "%~2" == "" (
  Setlocal EnableDelayedExpansion
  Echo/Args:"!ParamErr:%Arg1% =!" Ignored. %~n0 only accepts 1 Arg.
  Call "%~f0" "/?"
  Endlocal
  Echo/Continue with Arg1:"%Arg1%" [Y]/[N]?
  For /F "Delims=" %%G in ('Choice /N /C:YN')Do if "%%G" == "N" Exit /B
 )
:# /Dir Switch - Display all image paths with matching extensions in tree of current Directory
 If Not "%Arg1:/Dir=%" == "%Arg1%" (
  Dir /B /S "*.jpg" "*.png" "*.bmp" | More
  Exit /B
 )

:# Usage test and output

 If Not "%Arg1:/?=%" == "%Arg1%" (
  Echo/ %~n0 Usage:
  Echo/
  Echo/ %~n0 ["wallpaper filepath" ^| "Search term"]
  Echo/      Search times should include wildcard/s: * ? and / or extension as appropriate
  Echo/ Example:
  Echo/      Search for and select from .jpg files containing Dragon in the filename:
  Echo/     %~n0 "*Dragon*.jpg"
  Echo/
  Echo/ %~n0 [/Dir] - output list of available .jpg .png and .bmp files in the directory tree
  Echo/ %~n0 [/?] - help output
  Exit /B
 )

 Set "Wallpaper=%Arg1%"

:# Arg1 Not a valid path; Offer Addition of Wildcards to SearchTerm If not Present as Bookends
 If not exist "%Wallpaper%" If not "%Wallpaper:~0,1%" == "*" If not "%Wallpaper:~,-1%" == "*" (
  Echo/Add wildcards to "%Wallpaper%" {"*%Wallpaper%*"} [Y]/[N]?
  For /F "Delims=" %%G in ('Choice /N /C:YN')Do if "%%G" == "Y" Set "Wallpaper=*%Wallpaper%*"
 )

:# To support Search Terms run script in Top level of Directory containing Images; Find Full Path in Tree.

 PUSHD "%Userprofile%\Pictures"
 Set "Matches=0"
 (For /F "Delims=" %%G in ('Dir /B /S "%Wallpaper%"')Do (
   Set "Wallpaper=%%~fG"
   Set /A Matches+=1
   Call Set "Img[%%Matches%%]=%%~fG"
 )) 2> Nul

:# Determine if Target Wallpaper is Current Wallpaper; Notify and Exit
 reg query "HKEY_Current_User\Control Panel\desktop" -v wallpaper | %__AppDir__%findstr.exe /LIC:"%Wallpaper%" && (
  Echo/Wallpaper already applied.
  Exit /B
 )

:# Enable environment for macro expansion, Arrays and code block variable operations
  Setlocal EnableExtensions EnableDelayedExpansion

 If NOT %Matches% GTR 1 Goto :Apply

:# Report When Multiple Matches found; Offer menu containing up to first 36 matches [ limit of menu macro ]

If %Matches% GTR 36 Set Matches=36

(Set \n=^^^

%= Newline var \n for multi-line macro definition - Do not modify. =%)

==================================================================
:# Menu macro escaped for Definition with DelayedExpansion Enabled

:# IMPORTANT - RESERVED VARIABLES: Menu CH# CHCS Options Option Opt[i] Option.Output Cholist DIV

:# Key index list Allows 36 menu options. Component of Menu Macro
 Set "ChoList=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

:# Get console width for dividing line
 for /F "usebackq tokens=2* delims=: " %%W in (`mode con ^| %__APPDIR__%findstr.exe /LIC:"Columns"`) do Set /A "Console_Width=%%W"

:# Build dividing line for menu output.
 Set "DIV=" & For /L %%i in (2 1 %Console_Width%)Do Set "DIV=!DIV!-"

:# Menu macro Usage: %Menu% "quoted" "list of" "options"

     Set Menu=For %%n in (1 2)Do if %%n==2 (%\n%
%= Output Dividing Line                 =%  Echo(^^!DIV^^!%\n%
%= Reset CH# index value for Opt[#]     =%  Set "CH#=0"%\n%
%= Undefine choice option key list      =%  Set "CHCS="%\n%
%= For Each in list;                    =%  For %%G in (^^!Options^^!)Do (%\n%
%= For Option Index value               =%   For %%i in (^^!CH#^^!)Do (%\n%
%= Build the Choice key list and Opt[#] =%    Set "CHCS=^!CHCS^!^!ChoList:~%%i,1^!"%\n%
%= array using the character at the     =%    Set "Opt[^!ChoList:~%%i,1^!]=%%~G"%\n%
%= current substring index.             =%    Set "option.output=%%~G"%\n%
%= Display ; removing # variable prefix =%    Echo([^^!ChoList:~%%i,1^^!] ^^!Option.output:#=^^!%\n%
%= Increment Opt[#] Index var 'CH#'     =%    Set /A "CH#+=1"%\n%
%= Close CH# loop                       =%   )%\n%
%= Close Options loop                   =%  )%\n%
%= Output Dividing Line                 =%  Echo(^^!DIV^^!%\n%
%= Select option by character index     =%  For /F "Delims=" %%o in ('%__APPDIR__%Choice.exe /N /C:^^!CHCS^^!')Do (%\n%
%= Assign return var 'OPTION' with the  =%   Set "Option=^!Opt[%%o]^!"%\n%
%= value selected from Opt[CH#] array.  =%   If /I "^!Option^!" == "Exit" Exit /B 2%\n%
%= Return to previous script on Exit    =%  )%\n%
%= Capture Macro input - Options List   =% )Else Set Options=
========================================== ::: End Menu Definition

:# Notify match count

 Echo/%Matches% Files Matched:"!Arg1!"

:# Use match count to build options list for Menu macro from IMG[ Array. Restricted to first 36 matches.
 
 Set "Menu.Options="
 For /L %%i in (1 1 %Matches%)Do Set "Menu.Options=!Menu.Options! "!Img[%%i]!""

:# Call Menu macro

 %Menu% %Menu.Options%

:# Notify selected option

 Echo(Wallpaper Selected = !Option!
 Set "Wallpaper=%Option%"

:Apply

:# Pipe Filepath to Powershell; Capture as Powershell Variable within Pipe; Exit on Return.
 Echo/!Wallpaper!| powershell.exe -noprofile "$Image = $input | ?{$_}; iex (${%~f0} | out-string)"
 Endlocal
 POPD
Exit /B 0

:# The below line Marks the end of a Powershell comment Block; And the End of the Batch Script. 
: end batch / begin powershell #>

<#
 Function Source: https://www.joseespitia.com/2017/09/15/set-wallpaper-powershell-function/
#>

Function Set-WallPaper {
 [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]$Image
    )

Add-Type -TypeDefinition @" 
using System; 
using System.Runtime.InteropServices;

public class Params
{ 
    [DllImport("User32.dll",CharSet=CharSet.Unicode)] 
    public static extern int SystemParametersInfo (Int32 uAction, 
                                                   Int32 uParam, 
                                                   String lpvParam, 
                                                   Int32 fuWinIni);
}
"@ 

$SPI_SETDESKWALLPAPER = 0x0014
$UpdateIniFile = 0x01
$SendChangeEvent = 0x02

$RefreshIni = $UpdateIniFile -bor $SendChangeEvent

$ret = [Params]::SystemParametersInfo($SPI_SETDESKWALLPAPER, 0, $Image, $RefreshIni)
}

If (Test-Path $Image) {
    Set-WallPaper -Image $Image
    write-output "Wallpaper Updated."
}else {
    write-output "Wallpaper Does not exist in the Directory Tree."
}

Solution 2:[2]

My Employer has PowerShell constrained language mode on and blocks vbs files from being run in user context. While not as immediate, our solution was to delete %Appdata%\Microsoft\windows\themes\transcodedwallpaper from all user profiles so that it must recreate upon next restart.

I know this file exists if your source image is a jpg but may not if you had a bmp. It's possible changing the registry key HKCU\control panel\desktop WallPaper "file path" to something different, it will switch on next restart.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Iconiu