Jump to content
  • entries
    7
  • comments
    7
  • views
    377

OLD - Boot and Logon wallpaper generation using PowerShell.


Latest version of scripts and information can be found on: https://github.com/DJ-1701/GenerateWallpaper

 

 

 

 

 

 

 

 

 

 

 

 

Old information below...

 

The following details shows you how to create Boot and Logon wallpapers using existing wallpaper and adding an overlay of text which can display your school name, computer name, etc via PowerShell scripts which I have created and you may reuse, edit, butcher, etc. :).

 

Examples of this style can be found below:

 

Boot

backgroundDefault.thumb.jpg.7be3db1e8eb30371003a462c0212b186.jpg

 

Logon

LogonInfo.thumb.jpg.225bee33e1373888afe2508577847514.jpg

 

For this exercise we are going to use some pre-created wallpapers for Windows 10 in 19x6 (aka Widescreen) and 4x3 (aka Standard) resolutions, which can be downloaded here.

 

Extract the zip file to a folder with the School’s name. So, the folder path to both directories should be:

SchoolName\Wallpaper\4x3

SchoolName\Wallpaper\19x6

 

Feel free to have a look at the images in the folder, and delete and add images as you see fit. There are around 280MB worth of images, so you may want to delete some if your machines don’t have much space. After you have finished, copy the SchoolName directory to your Domain Controller’s netlogon share (i.e. \\FQDN\netlogon - where FQDN is the fully qualified domain name for your active directory domain).

 

Next we are going to take a look at the basic code.

 

Update Wallpaper

# Wallpaper folder source.
$Domain = (Get-WmiObject -Class Win32_ComputerSystem).Domain
$NetworkSource = "\\$Domain\NetLogon\SchoolName\Wallpaper"
$LocalSource = "$Env:ProgramFiles\SchoolName\Wallpaper"

# Custom wallpaper override file.
# Note: Value used to prevent deletion of local file when mirroring.
$Override = "$LocalSource\Override.jpg"

# Path to robocopy command.
$WinDir = (Get-Childitem env:WinDir).Value
$Robocopy = "$WinDir\System32\Robocopy.exe"
If (!(Test-Path($Robocopy)))
{
   Write-Host "$Robocopy does not exist."
   Exit
}

If (!(Test-Path($NetworkSource)))
{
   Write-Host "$NetworkSource does not exist."
   Exit
}

If (!(Test-Path($LocalSource)))
{
     New-Item -ItemType directory -Path $LocalSource
}

# Update local wallpapers.
&$Robocopy "$NetworkSource" "$LocalSource" /MIR /XF "$Override" /R:1 /W:1 /NP

 

Copy and paste the code above into PowerShell ISE, so you can create a PS1 file, and test the code if you so wish.

 

Please note:

  • PowerShell ISE needs to be run as an Administrator for certain aspects of the script to work.
  • Rename SchoolName in the script to the actual School Name (i.e. the folder you just copied to you Domain Controller’s netlogon share).

Save the script as \\FQDN\netlogon\Update Wallpaper.ps1 (where FQDN is the fully qualified domain name for your active directory domain).

 

When running the script as an Administrator, you should find this will copy the SchoolName folder down from the netlogon share to the C:\Program Files folder on the local computer.

 

Boot Info

# Text for the wallpaper.
$TextLabel = "School Address Here`r`nTelephone: Telephone Number Here`r`nComputer Name: "+((Get-Childitem env:ComputerName).Value)
$TextSizePoint = 18

# Text box colour.
$BoxRed = 22
$BoxGreen = 176
$BoxBlue = 221

# Text colour.
$TextRed = 255
$TextGreen = 255
$TextBlue = 255

# Wallpaper source folder.
$LocalSource = "$Env:ProgramFiles\SchoolName\Wallpaper"

# Custom wallpaper override file.
$Override = "$LocalSource\Override.jpg"

# Completed wallpaper destination location.
$WinDir = (Get-Childitem env:WinDir).Value
$SystemBackgroundDir = "$WinDir\system32\oobe\info\backgrounds"
$DestinationFile = "$SystemBackgroundDir\backgroundDefault.jpg"

If (!(Test-Path($LocalSource)))
{
   Write-Host "$LocalSource does not exist."
   Exit
}

If (!(Test-Path("$SystemBackgroundDir")))
{
  New-Item -ItemType directory -Path "$SystemBackgroundDir"
}

# Find current screen resolution.
# Note: Interrogating [system.Windows.Forms.Screen] at boot returns false 1024x768.
#       Therefore, a separate login script stores this data on user login to a registry key.
#       After which the PC can check this key. If data does not exist, it will use
#       recommended supported resolution data. If this fails, it will default to 1024x768.
$RegistryPath = "HKLM:\Software\MachineData"
If ((Test-Path $RegistryPath))
{
   If (((Get-ItemProperty -Path $RegistryPath).Horizontal -ne $null) -and ((Get-ItemProperty -Path $RegistryPath).Vertical -ne $null))
   {
       $Horizontal = [int]((Get-ItemProperty -Path $RegistryPath).Horizontal)
       $Vertical = [int]((Get-ItemProperty -Path $RegistryPath).Vertical)
   }
}
If ($Horizontal -eq $null) {$Horizontal = [int]((Get-WmiObject -Class Win32_VideoController).CurrentHorizontalResolution)}
If ($Vertical -eq $null) {$Vertical = [int]((Get-WmiObject -Class Win32_VideoController).CurrentVerticalResolution)}
If ($Horizontal -eq $null) {$Horizontal = [int]"1024"}
If ($Vertical -eq $null) {$Vertical = [int]"768"}

If ($Horizontal/$Vertical -le 1.4)
{
   $Ratio = "4x3"
}
Else
{
   $Ratio = "16x9"
}
$SourceDir = "$LocalSource\$Ratio"
If (!(Test-Path($SourceDir)))
{
   Write-Host "$SourceDir does not exist."
   Exit
}

# Select a random file as the source wallpaper.
$Files = (dir -Path $SourceDir\* -Recurse).FullName
$SourceFile = $Files | Get-Random

# If override wallpaper exists, change source file.
If ((Test-Path($Override)))
{
   $SourceFile = $Override
}

# If no source file exists, exit.
If (!(Test-Path($SourceFile)))
{
   Write-Host "$SourceFile does not exist."
   Exit
}
If ($? -eq $false)
{
   Write-Host "Null Source File."
   Exit
}

# Enable the creation of images.
Add-Type -AssemblyName System.Drawing

# Select a font, size and style.
$TextSizePixels=$TextSizePoint/0.75
$Font = New-Object System.Drawing.Font("Arial",$TextSizePixels,[Drawing.FontStyle]'Bold',"Pixel")

# Get source image from source file.
$SourceImage = [system.Drawing.Image]::FromFile($SourceFile)

# Create a new bitmap at the primary monitor resolution to construct an image.
$Bitmap = New-Object System.Drawing.Bitmap($Horizontal,$Vertical)

# Create image for editing.
$Image = [system.Drawing.Graphics]::FromImage($Bitmap)

# Ensure the image is clear.
$Image.Clear([system.Drawing.Color]::FromArgb(255,255,255,255))

# Set the ARGB values required for the text and text box.
$TextARGB = [system.Drawing.Color]::FromArgb(255,$TextRed,$TextGreen,$TextBlue)
$BoxARGB = [system.Drawing.Color]::FromArgb(255,$BoxRed,$BoxGreen,$BoxBlue)

# Set area for text placement.
$Rectangle = [system.Drawing.RectangleF]::FromLTRB(0, 0, $Horizontal, $Vertical)

# Set alignment format for the font.
$FormatFont = [system.Drawing.StringFormat]::GenericDefault
$FormatFont.Alignment = [system.Drawing.StringAlignment]::Center
$FormatFont.LineAlignment = [system.Drawing.StringAlignment]::Near

# Get text path Layout to work out text box co-ordinates.
$TextPath = New-Object System.Drawing.Drawing2D.GraphicsPath
$TextPath.AddString($TextLabel,$Font.FontFamily,$Font.Style,$Font.Size,$Rectangle,$FormatFont)

# Get co-ordinates of beginning and end of text.
$StartX = $Horizontal
$StartY = $Vertical
$EndX = 0
$EndY = 0
ForEach ($PathPointRow in $TextPath.PathPoints)
{
   If ($PathPointRow.X -le $StartX){$StartX = $PathPointRow.X}
   If ($PathPointRow.Y -le $StartY){$StartY = $PathPointRow.Y}
   If ($PathPointRow.X -gt $EndX){$EndX = $PathPointRow.X}
   If ($PathPointRow.Y -gt $EndY){$EndY = $PathPointRow.Y}
}
$EndX = $EndX - $StartX
$EndY = $EndY - $StartY

# Set up the brush colours for drawing text box and text string.
$BoxBrushColour = New-Object Drawing.SolidBrush $BoxARGB
$TextBrushColour = New-Object Drawing.SolidBrush $TextARGB

# Draw image.
$Image.DrawImage($SourceImage,0,0, $Horizontal, $Vertical)

# Draw box.
$Image.FillRectangle($BoxBrushColour,$StartX,$StartY,$EndX,$EndY)

# Draw text.
$Image.DrawString($TextLabel,$Font,$TextBrushColour,$Rectangle,$FormatFont)

# Find last boot time to display on Wallpaper.
$TextLabel = "Last Boot: "+((Get-Date).DateTime)

# Select a font, size and style.
$TextSizePoint = 10
$TextSizePixels=$TextSizePoint/0.75
$Font = New-Object System.Drawing.Font("Arial",$TextSizePoint,[Drawing.FontStyle]'Bold',"Pixel")

# Set alignment format for the font.
$FormatFont = [system.Drawing.StringFormat]::GenericDefault
$FormatFont.Alignment = [system.Drawing.StringAlignment]::Near
$FormatFont.LineAlignment = [system.Drawing.StringAlignment]::Far

# Get text path Layout to work out text box co-ordinates.
$TextPath = New-Object System.Drawing.Drawing2D.GraphicsPath
$TextPath.AddString($TextLabel,$Font.FontFamily,$Font.Style,$Font.Size,$Rectangle,$FormatFont)

# Get co-ordinates of beginning and end of text, and add padding for text box.
$StartX = $Horizontal
$StartY = $Vertical
$EndX = 0
$EndY = 0
ForEach ($PathPointRow in $TextPath.PathPoints)
{
   If ($PathPointRow.X -le $StartX){$StartX = $PathPointRow.X}
   If ($PathPointRow.Y -le $StartY){$StartY = $PathPointRow.Y}
   If ($PathPointRow.X -gt $EndX){$EndX = $PathPointRow.X}
   If ($PathPointRow.Y -gt $EndY){$EndY = $PathPointRow.Y}
}
$EndX = $EndX - $StartX + 15
$EndY = $EndY - $StartY + 15
$StartY = $StartY - 5
$StartX = $StartX - 5

# Set up the brush colours for drawing text box and text string.
$BoxBrushColour = New-Object Drawing.SolidBrush $BoxARGB
$TextBrushColour = New-Object Drawing.SolidBrush $TextARGB

# Draw box.
$Image.FillRectangle($BoxBrushColour,$StartX,$StartY,$EndX,$EndY)

# Draw text.
$Image.DrawString($TextLabel,$Font,$TextBrushColour,$Rectangle,$FormatFont)

# Save edited bitmap to file.
$Bitmap.Save($DestinationFile,[system.Drawing.Imaging.ImageFormat]::Jpeg)

# Clean up and remove objects.
$SourceImage.Dispose()
$Bitmap.Dispose()
$Image.Dispose()
$SourceDestinationFile

# Open saved file.
#Invoke-Item $DestinationFile

 

Copy and paste the code above into PowerShell ISE, so you can create a PS1 file, and test the code if you so wish.

 

Please note:

  • PowerShell ISE needs to be run as an Administrator for certain aspects of the script to work.
  • Edit the section after '$TextLabel = "' to change the text which is saved on the wallpaper.
  • Rename SchoolName in the script to the actual School Name (i.e. the folder you just copied to you Domain Controller’s netlogon share).

Save the script as \\FQDN\netlogon\SchoolName\Wallpaper\Boot Info.ps1 (where FQDN is the fully qualified domain name for your active directory domain).

 

When running the script as an Administrator, you should find this will grab a random file from the correct screen ratio folder (or nearest, if you have a non-standard/old widescreen) generate the text to overlay (so in this case School Address, Telephone Number and Computer Name in the top centre, and the Boot Time in the bottom left) and save the file to C:\Windows\System32\oobe\info\backgrounds\backgroundDefault.jpg.

 

The reason we are using this location by default is because it is also the standard location Windows 7 looked to for a corporate wallpaper, the path can be changed on Windows 10 if you wish to place it elsewhere.

 

Please note that the wallpaper will not change until we update group policy to force this new file, but you can view the output in the file mentioned above.

 

Logon Info

# Text for the wallpaper.
$TextLabel = "School Address Here`r`n`r`nUser Name: "+($env:USERNAME)+"`r`nComputer Name: "+($env:COMPUTERNAME)+"`r`nModel: "+((Get-WmiObject Win32_ComputerSystem).Model)+"`r`nSerial Number: "+((Get-WmiObject Win32_ComputerSystemProduct).IdentifyingNumber)
$TextSizePoint = 12

# Text box colour.
$BoxRed = 0
$BoxGreen = 125
$BoxBlue = 255

# Text colour.
$TextRed = 255
$TextGreen = 255
$TextBlue = 255

# Wallpaper source folder.
$LocalSource = "$Env:ProgramFiles\SchoolName\Wallpaper"

# Completed wallpaper destination location.
$DestinationFile = "$env:temp\LogonInfo.jpg"

# Clear theme cache files.
Remove-Item -Path "$($env:APPDATA)\Microsoft\Windows\Themes\*" -Recurse -Force -ErrorAction SilentlyContinue

# Ensure image is set to Stretch to screen resolution and not tile.
Set-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name WallpaperStyle -Value "2" -Force
Set-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name TileWallpaper -Value "0" -Force

If (!(Test-Path($LocalSource)))
{
   Write-Host "$LocalSource does not exist."
   Exit
}

# Find current screen resolution.
# Note: Interrogating [system.Windows.Forms.Screen] at boot returns false 1024x768.
#       Therefore, this login script stores the data on user login to a registry key.
#       After which the boot script can check this key. If data does not exist, it will use
#       recommended supported resolution data. If this fails, it will default to 1024x768.
[void] [system.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$RegistryPath = "HKLM:\Software\MachineData"
$Horizontal = [int]([system.Windows.Forms.Screen]::AllScreens[0]).Bounds.Width
$Vertical = [int]([system.Windows.Forms.Screen]::AllScreens[0]).Bounds.Height
If (!(Test-Path $RegistryPath)) {New-Item -Path $RegistryPath -Force}
New-ItemProperty -Path $RegistryPath -Name "Horizontal" -Value $Horizontal -PropertyType DWORD -Force
New-ItemProperty -Path $RegistryPath -Name "Vertical" -Value $Vertical -PropertyType DWORD -Force
If ($Horizontal -eq $null) {$Horizontal = [int]((Get-WmiObject -Class Win32_VideoController).CurrentHorizontalResolution)}
If ($Vertical -eq $null) {$Vertical = [int]((Get-WmiObject -Class Win32_VideoController).CurrentVerticalResolution)}
If ($Horizontal -eq $null) {$Horizontal = [int]"1024"}
If ($Vertical -eq $null) {$Vertical = [int]"768"}

If ($Horizontal/$Vertical -le 1.4)
{
   $Ratio = "4x3"
}
Else
{
   $Ratio = "16x9"
}
$SourceDir = "$LocalSource\$Ratio"
If (!(Test-Path($SourceDir)))
{
   Write-Host "$SourceDir does not exist."
   Exit
}

# Select a random file as the source wallpaper.
$Files = (dir -Path $SourceDir\* -Recurse).FullName
$SourceFile = $Files | Get-Random

# If username does not start with Student, look to see if the user has a personal wallpaper they wish to use instead.
If (!(($env:USERNAME) -like "Student*"))
{
   If (Test-Path("$env:userprofile\Documents\Wallpaper\Wallpaper.jpg"))
   {
       $SourceFile = "$env:userprofile\Documents\Wallpaper\Wallpaper.jpg"
   }
   ElseIf (Test-Path("$env:homeshare\Wallpaper\Wallpaper.jpg"))
   {
       $SourceFile = "$env:homeshare\Wallpaper\Wallpaper.jpg"
   }
}

# If no source file exists, exit.
If (!(Test-Path($SourceFile)))
{
   Write-Host "$SourceFile does not exist."
   Exit
}
If ($? -eq $false)
{
   Write-Host "Null Source File."
   Exit
}

# Use .Net Framework to create a class to update and refresh the Wallpaper.
Add-Type @”
   using System;
   using System.Runtime.InteropServices;
   using Microsoft.Win32;

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

           public static void Refresh(string path) 
           {
               SystemParametersInfo( 20, 0, path, 0x01 | 0x02 ); 
           }
       }
   }
“@

# Enable the creation of images.
Add-Type -AssemblyName System.Drawing

# Select a font, size and style.
$TextSizePixels=$TextSizePoint/0.75
$Font = New-Object System.Drawing.Font("Arial",$TextSizePixels,[Drawing.FontStyle]'Bold',"Pixel")

# Get source image from source file.
$SourceImage = [system.Drawing.Image]::FromFile($SourceFile)

# Create a new bitmap at the primary monitor resolution to construct an image.
$Bitmap = New-Object System.Drawing.Bitmap($Horizontal,$Vertical)

# Create image for editing.
$Image = [system.Drawing.Graphics]::FromImage($Bitmap)

# Ensure the image is clear.
$Image.Clear([system.Drawing.Color]::FromArgb(255,255,255,255))

# Set the ARGB values required for the text and text box.
$TextARGB = [system.Drawing.Color]::FromArgb(255,$TextRed,$TextGreen,$TextBlue)
$BoxARGB = [system.Drawing.Color]::FromArgb(255,$BoxRed,$BoxGreen,$BoxBlue)

# Set area for text placement.
$Rectangle = [system.Drawing.RectangleF]::FromLTRB(0, 0, $Horizontal, $Vertical)

# Set alignment format for the font.
$FormatFont = [system.Drawing.StringFormat]::GenericDefault
$FormatFont.Alignment = [system.Drawing.StringAlignment]::Far
$FormatFont.LineAlignment = [system.Drawing.StringAlignment]::Near

# Get text path Layout to work out text box co-ordinates.
$TextPath = New-Object System.Drawing.Drawing2D.GraphicsPath
$TextPath.AddString($TextLabel,$Font.FontFamily,$Font.Style,$Font.Size,$Rectangle,$FormatFont)

# Get co-ordinates of beginning and end of text, and add padding for text box.
$StartX = $Horizontal
$StartY = $Vertical
$EndX = 0
$EndY = 0
ForEach ($PathPointRow in $TextPath.PathPoints)
{
   If ($PathPointRow.X -le $StartX){$StartX = $PathPointRow.X}
   If ($PathPointRow.Y -le $StartY){$StartY = $PathPointRow.Y}
   If ($PathPointRow.X -gt $EndX){$EndX = $PathPointRow.X}
   If ($PathPointRow.Y -gt $EndY){$EndY = $PathPointRow.Y}
}
$EndX = $EndX - $StartX + 5
$EndY = $EndY - $StartY + 10
$StartY = $StartY - 5
$StartX = $StartX

# Set up the brush colours for drawing text box and text string.
$BoxBrushColour = New-Object Drawing.SolidBrush $BoxARGB
$TextBrushColour = New-Object Drawing.SolidBrush $TextARGB

# Draw image.
$Image.DrawImage($SourceImage,0,0, $Horizontal, $Vertical)

# Draw box.
$Image.FillRectangle($BoxBrushColour,$StartX,$StartY,$EndX,$EndY)

# Draw text.
$Image.DrawString($TextLabel,$Font,$TextBrushColour,$Rectangle,$FormatFont)

# Save edited bitmap to file.
$Bitmap.Save($DestinationFile,[system.Drawing.Imaging.ImageFormat]::Jpeg)

# Clean up and remove objects.
$SourceImage.Dispose()
$Bitmap.Dispose()
$Image.Dispose()
$SourceDestinationFile

# Open saved file.
#Invoke-Item $DestinationFile

# Update wallpaper.
[Wallpaper.UpdateImage]::Refresh($DestinationFile)

 

Copy and paste the code above into PowerShell ISE, so you can create a PS1 file, and test the code if you so wish.

 

Please note:

  • PowerShell ISE needs to be run as an Administrator for certain aspects of the script to work.
  • Edit the section after '$TextLabel ="' to change the text which is saved on the wallpaper.
  • Rename SchoolName in the script to the actual School Name (i.e. the folder you just copied to you Domain Controller’s netlogon share).

Save the script as \\FQDN\netlogon\Logon Info.ps1 (where FQDN is the fully qualified domain name for your active directory domain).

 

When running the script as an Administrator, you should find this will grab a random file from the correct screen ratio folder (or nearest, if you have a non-standard/old widescreen) generate the text to overlay (so in this case School Address, User Name, Computer Name, Model and Serial Number in the top right) and save the file to the user’s temporary folder %Temp%\LogonInfo.jpg

On a typical computer this would be: C:\Users\%Username%\AppData\Local\Temp\LogonInfo.jpg[/Code]

 

This script will also grab the most accurate data of the screens current resolution and store it in the registry location HKEY_LOCAL_MACHINE\Software\MachineData, which can then also be used by the Boot Info script.

 

Please note that the wallpaper will not change until we update group policy to force this new file, but you can view the output in the folder mentioned above.

 

[b]Group Policy

 

[/b]The group policy settings to enforce these wallpapers are as follows.

 

For the logon wallpaper, this will affect User Policy, so either create a new policy for the users, or edit an existing one and:

 

[/size]

  1. [size=1]Go to User Configuration -> Policies -> Windows Settings -> Scripts (Logon/Logoff) -> Logon, and then click on the PowerShell Scripts tab, press Add, and for the script name type in the full path you stored the logon script (i.e. \\FQDN\netlogon\Logon Info.ps1).[/size]
  2. [size=1]Go to User Configuration -> Policies -> Administrative Templates -> Desktop -> Desktop -> Desktop Wallpaper, and enable the policy, specifying the location as %temp%\LogonInfo.jpg and setting the wallpaper style to Stretch.[/size]

[size=1]

For the boot wallpaper, this will affect Computer Policy, so either create a new policy for the machines, or edit an existing one and:

 

[/size]

  1. [size=1]Go to User Configuration -> Policies -> Windows Settings -> Scripts (Logon/Logoff) -> Logon, and then click on the PowerShell Scripts tab, press Add, and for the script name type in the full path you stored the Update Wallpapers script (i.e. \\FQDN\netlogon\Update Wallpapers.ps1), next add another script name again, this time type the full path for the boot script (i.e. C:\Program Files\SchoolName\Wallpaper\Boot Info.ps1).[/size]
  2. [size=1]Go to User Configuration -> Policies -> Administrative Templates -> Control Panel -> Personalization -> Force a specific default lock screen and logon image, and enable the policy, specifying the location as:
    [Code]C:\Windows\System32\oobe\info\backgrounds\backgroundDefault.jpg[/Code]

    [/size]

Edited by DJ-1701

2 Comments


Recommended Comments

philellis

Posted

Hi DJ-1701

 

This seems to work perfectly for what we're wanting to achieve however are unable to run the PowerShell script with admin credentials on login which is why I think it's not replicating for standard users. Add to that Microsoft 'patching' group policy preferences to run as a different user this has become a bit of an issue. Do you have any advice /pointers?

 

Cheers

DJ-1701

Posted

Hi Philellis,

 

If the logon script can't/doesn't run as an administrator the file will still be generated, the only thing this would break is storing the resolution in the HKEY_LOCAL_MACHINE\Software\MachineData registry key. A way around that would be to set the machine GPO to create the key in Group Policy Preference, and after that in Policies\Windows Settings\Security Settings\Registry create add the key and allow access to the Authenticated Users to write to this key so the current resolution can be stored there.

 

Hope this helps,

 

DJ

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...