1

I was given a challenge to solve for making a little fun in the office. So I've tried to setup a VM lab with a windows server 2012 R2 & client Windows 10 to test this on.

The challenge I am facing:

Windows 10 is not always refreshing wallpaper when set, using the command by using the psexec:

rundll32.exe user32.dll, UpdatePerUserSystemParameters, 1, true

This seems to be due to a limitation in rundll32.exe or user32.dll not sure why.

I instead have to use a new theme that I have created by copy that to the client and load it with psexec to present it to the user instantly without logoff or restart. Although sometimes it does just not work or it simply just make the background black, like it's removing the wallpaper completely when I run the script more times to ensure that it works even though how many times I run it. Keep in mind this script is dependent on the client is online by that means that the DNS is working proper and you can also ping the host.

How can I ensure that the wallpaper is always being refreshed and working? - and is there a better method of this you can find, then kindly let me know because I tried to search on the internet but could not find anything working as good as this I've made so far on Windows 10 through powershell.

The script I currently got working right now is the following:

Download the source code here:

  • save this as ChangeDesktopBackgroundRemotely.ps1 -- Main script you run
  • save this as newtheme.theme in "C:\tmp" on your server
  • save this as refreshbg.ps1 in "C:\tmp" on your server
  • save FCK.jpg as FCK.jpg in "C:\tmp" on your server
  • save aalborg.jpg as aalborg.jpg in "C:\tmp" on your server
R3verse
  • 71
  • 2
  • 8
  • 1
    Why script this at all, when you can just do this in a [GPO](https://www.bing.com/search?q=chage+wallpaper+gpo+windows+10&form=ANNTH1&refig=6d7b1e83c2af4802a0c6d6095ddfd670&sp=-1&pq=chage+wallpaper+gpo+windows+10&sc=1-30&qs=n&sk=&cvid=6d7b1e83c2af4802a0c6d6095ddfd670)? – postanote Nov 07 '20 at 22:03
  • @postanote - Yes, that is true, but since I am running this in the office, I do not have access to GPO so I am using psexec to get around this, I can see it's running the powershell script on the other pc when doing it, so it works - but the intention of the wallpaper is always being changed no matter how many times I run the script should work but it just did not. Either it removed the bagground or something else bagground set. I am testing atm in my VM lab with a windows 10 and a windows server 2012 R2, so it should be able to work without GPO that is the whole idea. – R3verse Nov 08 '20 at 17:26

1 Answers1

0

Edit2

Remarks This function is intended for use with applications that allow the user to customize the environment.

End Edit2


Edit

By using PsExec you are starting a program in a different desktop on the target computer. This is a security thing. No-one can mess with a logged on user.

You are changing the wallpaper of an invisible desktop.

As I said use Task Scheduler with Only run when user logged on.

End Edit


There is only one supported way to change wallpaper.

Public Declare Unicode Function SystemParametersInfoW Lib "user32" (ByVal uAction As Integer, ByVal uParam As Integer, ByVal lpvParam As String, ByVal fuWinIni As Integer) As Integer
Public Const SPI_SETDESKWALLPAPER = 20
Public Const SPIF_SENDWININICHANGE = &H2
Public Const SPIF_UPDATEINIFILE = &H1

Ret = SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, FName, SPIF_SENDWININICHANGE + SPIF_UPDATEINIFILE)

See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow

Also see https://learn.microsoft.com/en-au/windows-server/administration/windows-commands/rundll32 which says "Rundll32 can only call functions from a DLL explicitly written to be called by Rundll32".

This is how it must be written

 void CALLBACK
 EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow); 

In programming we write contractual code, that is to specifications. So the only place you would search is https://learn.microsoft.com.

  • How would you put that into a powershell script ? :). It seems like you are using the same function here as I do in the powershell script I've posted: save this https://pastebin.com/5YhaeTfT as refreshbg.ps1 in "C:\tmp" on your server. But also I am not looking for a "supported" way, I am just looking for a way that works every time on windows 10 :-) – R3verse Nov 07 '20 at 20:54
  • *I am just looking for a way that works every time on windows 10* That would be the supported way. Your answer is in the Powershell Help. See https://devblogs.microsoft.com/scripting/use-powershell-to-interact-with-the-windows-api-part-1/ – user14122392 Nov 07 '20 at 21:14
  • Okay so if you would edit the powershell script in order to implement the solution you suggested - how would you do it ? - like this ? https://pastebin.com/cpzZr0T7 – R3verse Nov 07 '20 at 21:46
  • I'm not a powershell programmer, its an abomination of a language. This is how to do it in another inbuilt Windows language https://winsourcecode.blogspot.com/2019/06/changewallpaper.html – user14122392 Nov 07 '20 at 21:50
  • 3
    @user14122392, [There is only one supported way to change wallpaper.]. This is not true. This has been doable via GPO for decades and [doing it via PowerShell script](https://www.bing.com/search?q=powershellgallery+%27powershell+change+windows+10+wallpaper%27&form=ANNTH1&refig=222b21775eaa4ccaa90ccfa48d56abe7&sp=-1&pq=powershell+change+windows+10+wallpaper%27&sc=1-39&qs=n&sk=&cvid=222b21775eaa4ccaa90ccfa48d56abe7) has been well covered for a long time. The 'abomination' feeling, is a stance one can take for any language; after 4+decades, I've seen my share of them. IMHO PS is not one of them. – postanote Nov 07 '20 at 22:10
  • Yes those powershell scripts do it the supported way. Link 1 is stupid and link 2 uses the one supported way. `public static extern int SystemParametersInfo (Int32 uAction, Int32 uParam, String lpvParam, Int32 fuWinIni);}` – user14122392 Nov 07 '20 at 22:58
  • @user14122392 already looked at that when I did do the code, and tried this since it's a VBS script, but did not work and did not find it persistently. postanote - Yes, that is true, but since I am running this in the office, I do not have access to GPO so I am using psexec to get around this, I can see it's running the powershell script on the other pc when doing it, so it works - but the intention of the wallpaper is always being changed no matter how many times I run the script should work but it just did not. Either it removed the bagground or something else bagground set. – R3verse Nov 07 '20 at 23:45
  • Anyone else got a better way to do this ? - because the only way I found was to do the following: Run some invoke-commands to set the new wallpaper path on remote computer and then run the psexec to run as the current logged in user by running the powershell refreshbg.ps1 and then open the newtheme.theme through psexec and also use psexec to refresh the wallpaper as the current user by using the "rundll32.exe user32.dll, UpdatePerUserSystemParameters, 1, true" with psexec – R3verse Nov 07 '20 at 23:48
  • You have to run code correctly. So using PSExec it is running on another desktop. So schedule it to run in Task Scheduler as the logged on user. See `schtasks /?` for one way of doing it. – user14122392 Nov 08 '20 at 00:33
  • @user14122392 So you would do it just like this? - that does not work. I have just tried. So far my script above https://pastebin.com/P1xJrNAb just set the background black and select a "solid" color somehow, instead of using the photo. Just also tested with a new task as the current logged in user with this script https://pastebin.com/ma3mT8ie and it seem to not do any chagne. Don't know what goes wrong lol. It does run the script with powershell but no change.. – R3verse Nov 08 '20 at 11:10
  • @user14122392 Can you give an example with the powershell script above how you would do it? :) - perhaps it's just me who are not see how this should work. Sometimes it's better to get more eyes on the task if you know what I mean – R3verse Nov 08 '20 at 11:42
  • I gave you a link to a VB.NET program which works and shows the principal parts of what you need to pass. Here it is again - https://winsourcecode.blogspot.com/2019/06/changewallpaper.html. But you need to run the code in the same desktop as the user. Task Scheduler can do that. – user14122392 Nov 08 '20 at 12:08
  • @user14122392 Still not working even thoguh I did got it running with powershell the new task as the current user, it does not change the wallpaper it stays the same. Not sure what is going on, but it actually seems like a limitation in windows or powershell since if I in the VM on windows 10 run the task with powershell it changes the background just fine, but not when I run the task it created. If you did setup a VMlab and tried the above solution let me know if you get any other result, because somehow it's still not working. Even though I did follow your instructions :( – R3verse Nov 08 '20 at 17:22
  • How do you know that? You must run it as the user in the interactive desktop on the target computer. In TS it must say *Run Only When User Is Logged In*. A user can have one visible and multiple invisible desktops running background tasks.. – user14122392 Nov 09 '20 at 06:03
  • @user14122392 I know this because that is the whole idea behind psexec that you can either run the process(meaning powershell script) as the current logged in user, or you can run it as NT\System account service. The script I've made was created with intention of running in the interactive destkop which I can see it does in my VM?. I can see the both machines when I am running the script as you can see the above setup I have a windows 2012 R2 server where I run the script from and a windows 10 client which I am executing the scripts on. – R3verse Nov 09 '20 at 14:57