Thank you for testing! Here’s why your
PowerShell set-wallpaper script might not work in autounattend.xml, and how to make it work reliably:
Why Doesn't It Work in autounattend.xml?
- Context:
<FirstLogonCommands>
should run as the user, but sometimes scripts in unattend run hidden, or before the shell/desktop is ready.
- Profile/Permissions:
- If run as SYSTEM (via SetupComplete or specialize), there's no visible user desktop.
- Wallpaper changes must occur in the real interactive user session after Explorer has loaded.
- Timing:
- If wallpaper is set before Explorer fully initializes the desktop, the registry is updated but wallpaper isn't visually refreshed.
- Some policies or OEM customizations can override user settings.
How to Fix It
Step 1: Confirm Command Runs as the Real User
Use
<FirstLogonCommands>
not
SetupComplete.cmd
, and make sure your script is referenced like this:
Code:
<FirstLogonCommands>
<SynchronousCommand wcm:action="add">
<Order>1</Order>
<Description>Set Wallpaper</Description>
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File C:\SetupFiles\SetWallpaper.ps1</CommandLine>
</SynchronousCommand>
</FirstLogonCommands>
- Do NOT use it in the specialize pass or system context!
Step 2: Add a Wait for Desktop Readiness
Add a small delay to ensure Explorer is loaded before changing the wallpaper:
Start-Sleep -Seconds 10
(e.g., right before the wallpaper code in your script)
Step 3: Updated Script with Delay and Logging
Code:
Start-Sleep -Seconds 10 # wait for user desktop to fully load
$url = '[url]https://images.pexels.com/photos/5007737/pexels-photo-5007737.jpeg[/url]'
$wallpaperPath = "$env:USERPROFILE\Pictures\downloaded_wallpaper.jpg"
Invoke-WebRequest -Uri $url -OutFile $wallpaperPath -UseBasicParsing -TimeoutSec 30
Set-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name Wallpaper -Value $wallpaperPath
Add-Type @'
using System.Runtime.InteropServices;
public class NativeMethods {
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
}
'@
[NativeMethods]::SystemParametersInfo(20, 0, $wallpaperPath, 3)
# Optional: Write a log file
"`n$((Get-Date).ToString()) Wallpaper set to $wallpaperPath" | Out-File -FilePath "$env:USERPROFILE\wallpaperlog.txt" -Append
Step 4: Test Manually
- Log in with a test user, open a PowerShell prompt as that user, and run your script manually. If it works interactively but not with unattend, then it's a timing/context problem in setup. The 10-15 second delay above usually fixes this.
Step 5: Check for Errors
- After your deployment, check for
wallpaperlog.txt
or any errors in %USERPROFILE%
. Missing file or access denied means script ran with wrong user/permissions.
Alternative (If This Still Fails)
- Use a Scheduled Task set to run at logon for every user, with highest privileges, like this (run once, then delete itself):
schtasks /create /tn "SetWallpaper" /tr "powershell.exe -ExecutionPolicy Bypass -File C:\SetupFiles\SetWallpaper.ps1" /sc onlogon /ru "$env:USERNAME"
This ensures the script runs in the right context no matter what the setup timing is.
Summary
- Always set wallpaper as the first interactive user, after the desktop is initialized.
- Add
Start-Sleep
(10-15s) at the start of your script to increase reliability via autounattend.
- For guaranteed results, use a scheduled task at user logon if unattended/passive setup context proves unreliable.
Try the above script and method, and let me know if you want a ready-to-use scheduled task XML or further troubleshooting!