1

I have a desktop background image (a picture) in a half-dozen different resolutions, that I'd like to deploy to a disparate collection of computers with different monitors and video cards and whatnot. Laptops, netbooks, desktops, widescreen, and even a couple of "tall" screens. I have images to cover most of the cases.

I would like Windows 7 to correctly pick the correct desktop background image via group policy.

Now, the logon screen is already done. The OEMBackground method is rather clever, and lets you copy files of different resolutions to the machine, and the logon app will calculate the aspect ratio of the monitor and match it to a file as closely as possible.

Is there any way to have that functionality on the desktop background as well?

Rob Bos
  • 824
  • 7
  • 8

1 Answers1

1

Hm. If you're lucky, the ScreenHeight and ScreenWidth properties of the Win32_DesktopMonitor WMI class will be filled out on the client, which means you can easily use a VB script or Powershell script to determine the computer's desktop resolution.

Get-WMIObject Win32_DesktopMonitor

Now that you know the computer's resolution, you can set the appropriate wallpaper like so. Credits to the author of the following script are in the comments:

#requires -version 2.0
## Set-Wallpaper - set your windows desktop wallpaper
###################################################################################################
## Usage:
##    Set-Wallpaper "C:\Users\Joel\Pictures\Wallpaper\Dual Monitor\mandolux-tiger.jpg" "Tile"
##    ls *.jpg | get-random | Set-Wallpaper
##    ls *.jpg | get-random | Set-Wallpaper -Style "Stretch"
###################################################################################################
## History:
##    v0.5  First release (on #PowerShell@irc.freenode.net)
##    v1.0  Public release (http://www.poshcode.org/488)
##          - Added Style: Tile|Center|Stretch
##    v1.1  This Release
##          - Added "NoChange" style to just use the style setting already set
##          - Made the Style parameter to the cmdlet optional
###################################################################################################

add-type @"
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace Wallpaper
{
   public enum Style : int
   {
       Tile, Center, Stretch, NoChange
   }


   public class Setter {
      public const int SetDesktopWallpaper = 20;
      public const int UpdateIniFile = 0x01;
      public const int SendWinIniChange = 0x02;

      [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
      private static extern int SystemParametersInfo (int uAction, int uParam, string lpvParam, int fuWinIni);

      public static void SetWallpaper ( string path, Wallpaper.Style style ) {
         SystemParametersInfo( SetDesktopWallpaper, 0, path, UpdateIniFile | SendWinIniChange );

         RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", true);
         switch( style )
         {
            case Style.Stretch :
               key.SetValue(@"WallpaperStyle", "2") ; 
               key.SetValue(@"TileWallpaper", "0") ;
               break;
            case Style.Center :
               key.SetValue(@"WallpaperStyle", "1") ; 
               key.SetValue(@"TileWallpaper", "0") ; 
               break;
            case Style.Tile :
               key.SetValue(@"WallpaperStyle", "1") ; 
               key.SetValue(@"TileWallpaper", "1") ;
               break;
            case Style.NoChange :
               break;
         }
         key.Close();
      }
   }
}
"@

cmdlet Set-Wallpaper {
Param(
   [Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
   [Alias("FullName")]
   [string]
   $Path
,
   [Parameter(Position=1, Mandatory=$false)]
   [Wallpaper.Style]
   $Style = "NoChange"
)
   [Wallpaper.Setter]::SetWallpaper( (Convert-Path $Path), $Style )
}

Notice that you have to P/Invoke user32.dll to set wallpaper, which may mean VB script might not be able to accomplish this.

Here's a much shorter, simpler way to do it, although it will probably require a logoff/logon to take effect:

Function Set-WallPaper($Value)
{    
  Set-ItemProperty -path 'HKCU:\Control Panel\Desktop\' -name wallpaper -value $value

  rundll32.exe user32.dll, UpdatePerUserSystemParameters

}

Method 2: Also, you can use GPO WMI filters on the same WMI class, and set a different wallpaper based on the results of that WMI filter. So for instance, you could either host all the variably-sized wallpapers on a network share, or you could use Group Policy to prestage all the wallpapers on each client. Then, make one GPO for each different size of wallpaper, and set the WMI filter on it to apply only if Win32_DesktopMonitor.ScreenWidth = 1920, and so on.

Ryan Ries
  • 55,011
  • 9
  • 138
  • 197
  • It would be nice to avoid a logon script, and it may come to that, but hell if the WMI filter idea isn't clever. I could set up an item-level target with WMI queries. I'll give that a shot. – Rob Bos Oct 15 '12 at 22:51
  • Specifically I point the wallpaper at a static filename and use the item level target to copy the correct file over. Resolution is unlikely to change very often so that should give the correct wallpaper after a reboot. – Rob Bos Oct 15 '12 at 22:53
  • Well, it works - target an item to Select * from Win32_DesktopMonitor where ScreenWidth='1280' and ScreenHeight='1024' - but it exposes an unrelated problem. If you don't have your official vendor video drivers, it doesn't seem to expose any WMI resolution values. Guess I have to sort that out first. – Rob Bos Oct 16 '12 at 00:53
  • Yeah, I noticed that it's not perfect as well, as I don't have those attributes populated on my desktop machine either. :( There are certainly other ways you could determine the desktop resolution of the client, but they might involve developing an executable and running it at logon. :\ – Ryan Ries Oct 16 '12 at 01:24