-
-
Save joegasper/3ab03b1147bb1135b8aabb09f38f6217 to your computer and use it in GitHub Desktop.
update wallpaper background image with powershell (like Sysinternals BGInfo)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# PS-BGInfo | |
# Powershell script that updates the background image with a random image from a folder and writes out system info text to it. | |
# run as a lower priority task | |
[System.Threading.Thread]::CurrentThread.Priority = 'BelowNormal' | |
# Configuration: | |
# Font Family name | |
$font="Input" | |
# Font size in pixels | |
$size=10.0 | |
# spacing in pixels | |
$textPaddingLeft = 10 | |
$textPaddingTop = 10 | |
$textItemSpace = 3 | |
$wallpaperImagesSource = "$Env:USERPROFILE\Pictures\wallpaper" | |
$wallpaperImageOutput = "$Env:USERPROFILE" | |
# Get local info to write out to wallpaper | |
$os = Get-CimInstance Win32_OperatingSystem | |
$release = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId | |
$cpu = (Get-WmiObject Win32_Processor).Name.Replace("Intel(R) Core(TM) ", "") | |
$BootTimeSpan = (New-TimeSpan -Start $os.LastBootUpTime -End (Get-Date)) | |
# get external IP address | |
$external = (Invoke-WebRequest -UseBasicParsing "ifconfig.me/ip").Content.Trim() | |
# get array of internal IPs | |
$ip = (Get-NetIPAddress | Where-Object {$_.InterfaceAlias -eq "Ethernet" -and $_.AddressFamily -eq "IPv4"}).IPAddress | |
$o = ([ordered]@{ | |
User = $os.RegisteredUser | |
Host = "$($os.CSName) `n$($os.Description)" | |
CPU = $cpu | |
RAM = "$([math]::round($os.TotalVisibleMemorySize / 1MB))GB" | |
OS = "$($os.Caption) `n$($os.OSArchitecture), $($os.Version), $release" | |
Boot = $os.LastBootUpTime | |
Uptime = "$($BootTimeSpan.Days) days, $($BootTimeSpan.Hours) hours" | |
Snapshot = $os.LocalDateTime | |
External = $external | |
}) | |
# loop through each IP address and add it to the object | |
$ipIndex = 1 | |
$ips | ForEach { | |
$o["IP" + $ipIndex] = $_ | |
$ipIndex++ | |
} | |
# original src: https://p0w3rsh3ll.wordpress.com/2014/08/29/poc-tatoo-the-background-of-your-virtual-machines/ | |
Function New-ImageInfo { | |
# src: https://github.com/fabriceleal/Imagify/blob/master/imagify.ps1 | |
param( | |
[Parameter(Mandatory=$True, Position=1)] | |
[object] $data, | |
[Parameter(Mandatory=$True)] | |
[string] $in, | |
[string] $font="Courier New", | |
[float] $size=12.0, | |
[float] $textPaddingLeft = 0, | |
[float] $textPaddingTop = 0, | |
[float] $textItemSpace = 0, | |
[string] $out="out.png" | |
) | |
[system.reflection.assembly]::loadWithPartialName('system') | out-null | |
[system.reflection.assembly]::loadWithPartialName('system.drawing') | out-null | |
[system.reflection.assembly]::loadWithPartialName('system.drawing.imaging') | out-null | |
[system.reflection.assembly]::loadWithPartialName('system.windows.forms') | out-null | |
$foreBrush = [System.Drawing.Brushes]::White | |
$backBrush = new-object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(192, 0, 0, 0)) | |
# Create Bitmap | |
$SR = [System.Windows.Forms.Screen]::AllScreens | Where-Object Primary | Select-Object -ExpandProperty Bounds | Select-Object Width,Height | |
Write-Output $SR >> "$wallpaperImageOutput\wallpaper.log" | |
$background = new-object system.drawing.bitmap($SR.Width, $SR.Height) | |
$bmp = new-object system.drawing.bitmap -ArgumentList $in | |
# Create Graphics | |
$image = [System.Drawing.Graphics]::FromImage($background) | |
# Paint image's background | |
$rect = new-object system.drawing.rectanglef(0, 0, $SR.width, $SR.height) | |
$image.FillRectangle($backBrush, $rect) | |
# add in image | |
$topLeft = new-object System.Drawing.RectangleF(0, 0, $SR.Width, $SR.Height) | |
$image.DrawImage($bmp, $topLeft) | |
# Draw string | |
$strFrmt = new-object system.drawing.stringformat | |
$strFrmt.Alignment = [system.drawing.StringAlignment]::Near | |
$strFrmt.LineAlignment = [system.drawing.StringAlignment]::Near | |
$taskbar = [System.Windows.Forms.Screen]::AllScreens | |
$taskbarOffset = $taskbar.Bounds.Height - $taskbar.WorkingArea.Height | |
# first get max key & val widths | |
$maxKeyWidth = 0 | |
$maxValWidth = 0 | |
$textBgHeight = 0 + $taskbarOffset | |
$textBgWidth = 0 | |
# a reversed ordered collection is used since it starts from the bottom | |
$reversed = [ordered]@{} | |
foreach ($h in $data.GetEnumerator()) { | |
$valString = "$($h.Value)" | |
$valFont = New-Object System.Drawing.Font($font, $size, [System.Drawing.FontStyle]::Regular) | |
$valSize = [system.windows.forms.textrenderer]::MeasureText($valString, $valFont) | |
$maxValWidth = [math]::Max($maxValWidth, $valSize.Width) | |
$keyString = "$($h.Name): " | |
$keyFont = New-Object System.Drawing.Font($font, $size, [System.Drawing.FontStyle]::Bold) | |
$keySize = [system.windows.forms.textrenderer]::MeasureText($keyString, $keyFont) | |
$maxKeyWidth = [math]::Max($maxKeyWidth, $keySize.Width) | |
$maxItemHeight = [math]::Max($valSize.Height, $keySize.Height) | |
$textBgHeight += ($maxItemHeight + $textItemSpace) | |
$reversed.Insert(0, $h.Name, $h.Value) | |
} | |
$textBgWidth = $maxKeyWidth + $maxValWidth + $textPaddingLeft | |
$textBgHeight += $textPaddingTop | |
$textBgX = $SR.Width - $textBgWidth | |
$textBgY = $SR.Height - $textBgHeight | |
$textBgRect = New-Object System.Drawing.RectangleF($textBgX, $textBgY, $textBgWidth, $textBgHeight) | |
$image.FillRectangle($backBrush, $textBgRect) | |
Write-Output $textBgRect >> "$wallpaperImageOutput\wallpaper.log" | |
$i = 0 | |
$cumulativeHeight = $SR.Height - $taskbarOffset | |
foreach ($h in $reversed.GetEnumerator()) { | |
$valString = "$($h.Value)" | |
$valFont = New-Object System.Drawing.Font($font, $size, [System.Drawing.FontStyle]::Regular) | |
$valSize = [system.windows.forms.textrenderer]::MeasureText($valString, $valFont) | |
$keyString = "$($h.Name): " | |
$keyFont = New-Object System.Drawing.Font($font, $size, [System.Drawing.FontStyle]::Bold) | |
$keySize = [system.windows.forms.textrenderer]::MeasureText($keyString, $keyFont) | |
Write-Output $valString >> "$wallpaperImageOutput\wallpaper.log" | |
Write-Output $keyString >> "$wallpaperImageOutput\wallpaper.log" | |
$maxItemHeight = [math]::Max($valSize.Height, $keySize.Height) + $textItemSpace | |
$valX = $SR.Width - $maxValWidth | |
$valY = $cumulativeHeight - $maxItemHeight | |
$keyX = $valX - $maxKeyWidth | |
$keyY = $valY | |
$valRect = New-Object System.Drawing.RectangleF($valX, $valY, $maxValWidth, $valSize.Height) | |
$keyRect = New-Object System.Drawing.RectangleF($keyX, $keyY, $maxKeyWidth, $keySize.Height) | |
$cumulativeHeight = $valRect.Top | |
$image.DrawString($keyString, $keyFont, $foreBrush, $keyRect, $strFrmt) | |
$image.DrawString($valString, $valFont, $foreBrush, $valRect, $strFrmt) | |
$i++ | |
} | |
# Close Graphics | |
$image.Dispose(); | |
# Save and close Bitmap | |
$background.Save($out, [system.drawing.imaging.imageformat]::Png); | |
$background.Dispose(); | |
$bmp.Dispose(); | |
# Output file | |
Get-Item -Path $out | |
} | |
#TODO: there in't a better way to do this than inline C#? | |
Add-Type @" | |
using System.Runtime.InteropServices; | |
namespace Wallpaper | |
{ | |
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 UpdateWallpaper (string path) | |
{ | |
SystemParametersInfo( SetDesktopWallpaper, 0, path, UpdateIniFile | SendWinIniChange ); | |
} | |
} | |
} | |
"@ | |
Function Set-Wallpaper { | |
# original src: http://powershell.com/cs/blogs/tips/archive/2014/01/10/change-desktop-wallpaper.aspx | |
param( | |
[Parameter(Mandatory=$true)] | |
$Path, | |
[ValidateSet('Center', 'Stretch', 'Fill', 'Tile', 'Fit')] | |
$Style = 'Center' | |
) | |
# this is likely to be the same every time | |
Set-ItemProperty -Path "HKCU:Control Panel\Desktop" -Name WallPaper -Value $Path | |
$ws = 0 | |
$tw = 0 | |
switch ( $Style ) | |
{ | |
'Center' { $ws = 0; $tw = 0; } | |
'Stretch' { $ws = 2; $tw = 0; } | |
'Fill' { $ws = 10; $tw = 0; } | |
'Tile' { $ws = 0; $tw = 1; } | |
'Fit' { $ws = 6; $tw = 0; } | |
} | |
Set-ItemProperty -Path "HKCU:Control Panel\Desktop" -Name WallpaperStyle -Value $ws | |
Set-ItemProperty -Path "HKCU:Control Panel\Desktop" -Name TileWallpaper -Value $tw | |
# wait 5 seconds | |
Start-Sleep -s 5 | |
[Wallpaper.Setter]::UpdateWallpaper( $Path ) | |
# alternate (I can't get these to work): | |
#& RUNDLL32.EXE user32.dll, UpdatePerUserSystemParameters, 1, True | |
#& RUNDLL32.EXE user32.dll, SystemParametersInfo, 20, 0, $Path, 3 | |
#RUNDLL32.EXE user32.dll,UpdatePerUserSystemParameters 1, True | |
} | |
# execute tasks | |
Write-Output $o > "$wallpaperImageOutput\wallpaper.log" | |
# get random wallpaper from a folder full of images | |
Get-ChildItem -Path "$wallpaperImagesSource\*" -Include *.* -Exclude current.jpg | Get-Random | Foreach-Object { Copy-Item -Path $_ -Destination "$wallpaperImagesSource\current.jpg" } | |
# create wallpaper image and save it in user profile | |
$WallPaper = New-ImageInfo -data $o -in "$wallpaperImagesSource\current.jpg" -out "$wallpaperImageOutput\wallpaper.png" -font $font -size $size -textPaddingLeft $textPaddingLeft -textPaddingTop $textPaddingTop -textItemSpace $textItemSpace | |
Write-Output $WallPaper.FullName >> "$wallpaperImageOutput\wallpaper.log" | |
# update wallpaper for logged in user | |
Set-Wallpaper -Path $WallPaper.FullName |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
' Win32_ProcessStartup info: https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-processstartup | |
' PriorityClass values | |
Const LOW = 64 ' Indicates a process with threads that run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle priority class is inherited by child processes. | |
Const BELOW_NORMAL = 16384 ' Indicates a process that has a priority higher than Idle but lower than Normal. | |
Const NORMAL = 32 ' Indicates a normal process with no special schedule needs. | |
Const ABOVE_NORMAL = 32768 ' Indicates a process that has a priority higher than Normal but lower than High | |
Const HIGH = 128 ' Indicates a process that performs time-critical tasks that must be executed immediately to run correctly. The threads of a high-priority class process preempt the threads of normal-priority or idle-priority class processes. An example is Windows Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a high-priority class CPU-bound application can use nearly all of the available cycles. Only a real-time priority preempts threads set to this level. | |
Const REALTIME = 256 ' Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes—including high-priority threads and operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush, or cause a mouse to be unresponsive. | |
' ShowWindow values | |
Const SW_HIDE = 0 ' Hides the window and activates another window. | |
Const SW_NORMAL = 1 ' Activates and displays a window. If the window is minimized or maximized, the system restores it to the original size and position. An application specifies this flag when displaying the window for the first time. | |
Const SW_SHOWMINIMIZED = 2 ' Activates the window, and displays it as a minimized window. | |
Const SW_SHOWMAXIMIZED = 3 ' Activates the window, and displays it as a maximized window. | |
Const SW_SHOWNOACTIVATE = 4 ' Displays a window in its most recent size and position. This value is similar to SW_NORMAL, except that the window is not activated. | |
Const SW_SHOW = 5 ' Activates the window, and displays it at the current size and position. | |
Const SW_MINIMIZE = 6 ' Minimizes the specified window, and activates the next top-level window in the Z order. | |
Const SW_SHOWMINNOACTIVE = 7 ' Displays the window as a minimized window. This value is similar to SW_SHOWMINIMZED, except that the window is not activated. | |
Const SW_SHOWNA = 8 ' Displays the window at the current size and position. This value is similar to SW_SHOW, except that the window is not activated. | |
Const SW_RESTORE = 9 ' Activates and displays the window. If the window is minimized or maximized, the system restores it to the original size and position. An application specifies this flag when restoring a minimized window. | |
Const SW_SHOWDEFAULT = 10 ' Sets the show state based on the SW_* value that is specified in the STARTUPINFO structure passed to the CreateProcess function by the program that starts the application. | |
Const SW_FORCEMINIMIZE = 11 ' Minimizes a window, even when the thread that owns the window stops responding. Only use this flag when minimizing windows from a different thread. | |
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") | |
Set objStartup = objWMIService.Get("Win32_ProcessStartup") | |
Set objConfig = objStartup.SpawnInstance_ | |
objConfig.PriorityClass = BELOW_NORMAL | |
objConfig.ShowWindow = SW_HIDE | |
Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process") | |
objProcess.Create "powershell.exe -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File C:\utils\PS-BGInfo.ps1", Null, objConfig, intProcessID |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment