PowerShell script to download Bing’s daily image as a wallpaper

Update: Python way for Mac posted here

There are few ways you can download Bing’s daily image and set it up as your wallpaper. The easiest way at the time of writing this post is to download Bing Desktop program by Microsoft. Or, you can just head over to Bing.com and download the image manually if you do not want to install more bloatware on your computer. Lastly, if you are like me, create a PowerShell script to automate downloading Bing’s daily image for you and set it up as your wallpaper without having to install any programs.

Jump to the script download at the end of this post if you wish to skip all the technical details.

Bing has an XML page that changes daily reflecting the wallpaper name, region, and resolution. Luckily for us, we can have PowerShell parse that XML info and download the Bing image for us.

First of, if you just want a simple script to download the latest Bing image to your computer, use this:
Note: Make sure you create a “Bing Wallpaper” folder inside your “Pictures” folder. This is where the Bing image will be downloaded

$Market = "en-US"
$Resolution = "1920x1080"
$ImageFileName = "wallpaper.jpg"
$DownloadDirectory = "$env:USERPROFILE\Pictures\Bing Wallpaper"
$BingImageFullPath = "$($DownloadDirectory)\$($ImageFileName)"

New-Item -ItemType directory -Path $DownloadDirectory

[ xml ]$Bingxml = (New-Object System.Net.WebClient).DownloadString("http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1&mkt=$($Market)");
$ImageUrl = "http://www.bing.com$($Bingxml.images.image.urlBase)_$($Resolution).jpg";

Invoke-WebRequest -UseBasicParsing -Uri $ImageUrl -OutFile "$BingImageFullPath";

Save the above code as “Get-Bing.ps1” or any other name you like. Launch PowerShell and execute the script .\Get-Bing.ps1

The above code simply goes to Bing’s XML page, finds the Bing image urlBase, adds the approperiate resolution and download the image. Very simple! And it can be simplified even more if needed be. This maybe all you need if you only want to manually download Bing’s daily image and move on. However, this code does not apply the image as a wallpaper.

At the very top of the script, you see parameters like market, resolution, file name, etc. Bing sometimes has different images for different geographical regions. There you can tell the script which region you want to download from. The available regions are: “en-US”,”zh-CN”,”ja-JP”,”en-AU”,”en-UK”,”de-DE”,”en-NZ”.

Resolution can also be changed to one of the following: 1366×768, 1920×1080, 1920×1200
1920×1080 is the highest resolution you can request WITHOUT the Bing logo watermark on it. Any higher resolution will have “Bing” logo watermark on the bottom right of the image.

$ImageFileName and $DownloadDirectory can be changed to anything you want. $ImageDirectory is where you want Bing image to download – In our case, this will be a folder called “Bing Wallpaper” inside your “Pictures” folder. $ImageFileName is what the downloaded Bing image will be called.

1920×1080 is the highest resolution you can request WITHOUT the Bing logo watermark on it

Setting downloaded Bing image as wallpaper

So far, everything is good and we get our Bing image downloaded to our desired location. We can also have the script set the downloaded image as a wallpaper immediately after download.

Note: the code below includes the code above plus new code

$Market = "en-US"
$Resolution = "1920x1080"
$ImageFileName = "wallpaper.jpg"
$DownloadDirectory = "$env:USERPROFILE\Pictures\Bing Wallpaper"
$BingImageFullPath = "$($DownloadDirectory)\$($ImageFileName)"

New-Item -ItemType directory -Path $DownloadDirectory

[ xml ]$Bingxml = (New-Object System.Net.WebClient).DownloadString("http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1&mkt=$($Market)");
$ImageUrl = "http://www.bing.com$($Bingxml.images.image.urlBase)_$($Resolution).jpg";

Invoke-WebRequest -UseBasicParsing -Uri $ImageUrl -OutFile "$BingImageFullPath";

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();
      }
   }
}
"@
[Wallpaper.Setter]::SetWallpaper( "$BingImageFullPath", 3 )

You see here the last line of the script, will take the downloaded Bing image and set it as a Wallpaper immediately after download.

The above two scripts will work great assuming that everything executed without a hiccup. However, they will NOT work and cause “black” desktop screen if:

– The script can not find the right directoty to download the image to.
– If there is no internet connectivity
– You may get a black wallpaper if the Bing image is corrupted or did not download correctly.

We can make few additions to the script to avoid any problems if any, for example:

– have the script automatically create a download directory for us if one does not exist.
– Check if we already have the latest image before fetching for a new one. (No point to download the same image again)
– Make sure the script downloaded an image before setting it as a wallpaper to avoid black wallpaper screen.
– Make sure we have internet connectivity before executing the script.

Making the script smart

$Market = "en-US"
$Resolution = "1920x1080"
$ImageFileName = "wallpaper.jpg"
$DownloadDirectory = "$env:USERPROFILE\Pictures\Bing Wallpaper"
$BingImageFullPath = "$($DownloadDirectory)\$($ImageFileName)"

While (!(Test-Connection -ComputerName bing.com -count 1 -Quiet -ErrorAction SilentlyContinue )) {
    Write-Host -ForegroundColor Red "Waiting for internet connection to continue..."
    Start-Sleep -Seconds 10
}

New-Item -ItemType directory -Force -Path $DownloadDirectory | Out-Null

[ xml ]$Bingxml = (New-Object System.Net.WebClient).DownloadString("http://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1&mkt=$($Market)");
$ImageUrl = "http://www.bing.com$($Bingxml.images.image.urlBase)_$($Resolution).jpg";

if ((Test-Path "$BingImageFullPath") -And ((Get-ChildItem "$BingImageFullPath").LastWriteTime.ToShortDateString() -eq (get-date).ToShortDatesTring())){
    Write-Host -ForegroundColor Green "You already have today's Bing image in: $DownloadDirectory"   
}
else {
    Invoke-WebRequest -UseBasicParsing -Uri $ImageUrl -OutFile "$BingImageFullPath";
    Write-Host -ForegroundColor Green "Today's Bing image downloaded to: $DownloadDirectory" 
}

While (!(Test-Path "$BingImageFullPath")) {
    Write-Host -ForegroundColor Yellow "Waiting for Bing image to finish downloading..."
    Start-Sleep -Seconds 10
}
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();
      }
   }
}
"@
[Wallpaper.Setter]::SetWallpaper( "$BingImageFullPath", 3 )

The script above will work every time you launch it. It will not download a new Bing image if you already have the latest one. It will automatically create a download directory for you if one doesn’t exist. It will download a new Bing image if the one you have is old. Lastly, wait for the Bing image to finish downloading and set it as a wallpaper.

Let me know in the comments if I have missed any scenario that may cause the script to error out and not run correctly.

Set the script to start every time you log on to Windows with Windows Task Scheduler.

Bonus

When you set a PowerShell script to run at startup, you get a little PowerShell window that quickly pops up and disappear on your desktop every time it loads. To avoid that, you can create a small VBS script that silently call the PowerShell script. That way, you will not see any quick popups every time the script loads. Both PowerShell and VBS scripts are included in the download below.

VBS script to silently call the PowerShell script

command = "powershell.exe -nologo -command .\Get-Bing.ps1"
set shell = CreateObject("WScript.Shell")
shell.Run command,0


Download Scripts

//////
Show Comments