param( [object]$Config, [string]$LogFile ) $ErrorActionPreference = "Continue" function Write-Log { param([string]$Message, [string]$Level = "INFO") $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message" Add-Content -Path $LogFile -Value $line -Encoding UTF8 } $ScriptDir = "C:\Windows\Setup\Scripts" $RenderScript = "$ScriptDir\DesktopInfo-Render.ps1" $BmpPath = "$ScriptDir\desktopinfo.bmp" if (-not (Test-Path $ScriptDir)) { New-Item -ItemType Directory -Path $ScriptDir -Force | Out-Null } # ----------------------------------------------------------------------- # Write the rendering script (runs on every logon as the user) # Layout: hostname (large bold, centered), then detail lines centered # ----------------------------------------------------------------------- Write-Log "Writing DesktopInfo render script to $RenderScript" -Level INFO $renderContent = @' # DesktopInfo-Render.ps1 # Collects system info and renders it centered on the desktop wallpaper. # Runs on every user logon via Scheduled Task. $ErrorActionPreference = "Continue" $LogFile = "C:\Windows\Setup\Scripts\desktopinfo.log" function Write-Log { param([string]$Message, [string]$Level = "INFO") Add-Content -Path $LogFile -Value "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message" -Encoding UTF8 } Write-Log "DesktopInfo render started" -Level INFO Add-Type -AssemblyName System.Drawing Add-Type -AssemblyName System.Windows.Forms Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; public class WallpaperApi { [DllImport("user32.dll", CharSet=CharSet.Auto)] public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni); } "@ -ErrorAction SilentlyContinue # ----------------------------------------------------------------------- # Collect system info # ----------------------------------------------------------------------- Write-Log "Collecting system info" $hostname = $env:COMPUTERNAME $userDomain = $env:USERDOMAIN $userName = $env:USERNAME $loggedUser = if ($userDomain -and $userDomain -ne $hostname) { "$userDomain\$userName" } else { "$hostname\$userName" } $osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue $osName = if ($osInfo) { $osInfo.Caption -replace "^Microsoft\s*", "" } else { "Windows" } $ramGB = if ($osInfo) { [math]::Round($osInfo.TotalVisibleMemorySize / 1024 / 1024, 1) } else { "?" } $cpuInfo = Get-CimInstance Win32_Processor -ErrorAction SilentlyContinue | Select-Object -First 1 $cpuCount = if ($cpuInfo) { $cpuInfo.NumberOfLogicalProcessors } else { "?" } $cpuSpeed = if ($cpuInfo) { $cpuInfo.MaxClockSpeed } else { "?" } $ips = (Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue | Where-Object { $_.IPAddress -ne "127.0.0.1" -and $_.PrefixOrigin -ne "WellKnown" } | Select-Object -ExpandProperty IPAddress) -join ", " if (-not $ips) { $ips = "N/A" } $csInfo = Get-CimInstance Win32_ComputerSystem -ErrorAction SilentlyContinue $domain = if ($csInfo -and $csInfo.PartOfDomain) { $csInfo.Domain } ` elseif ($csInfo -and $csInfo.Workgroup) { $csInfo.Workgroup.ToLower() } ` else { "N/A" } Write-Log "hostname=$hostname user=$loggedUser os=$osName ram=$($ramGB)GB cpu=${cpuCount}x${cpuSpeed}MHz ips=$ips domain=$domain" # ----------------------------------------------------------------------- # Screen dimensions # ----------------------------------------------------------------------- $screen = [System.Windows.Forms.Screen]::PrimaryScreen $width = if ($screen) { $screen.Bounds.Width } else { 1920 } $height = if ($screen) { $screen.Bounds.Height } else { 1080 } Write-Log "screen=${width}x${height}" # ----------------------------------------------------------------------- # Create bitmap and graphics context # ----------------------------------------------------------------------- $bmp = New-Object System.Drawing.Bitmap($width, $height) $g = [System.Drawing.Graphics]::FromImage($bmp) $g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::AntiAlias $g.Clear([System.Drawing.ColorTranslator]::FromHtml("#556364")) # ----------------------------------------------------------------------- # Fonts and brushes # ----------------------------------------------------------------------- $fontName = "Segoe UI" $fontTitle = New-Object System.Drawing.Font($fontName, 36, [System.Drawing.FontStyle]::Bold) $fontBold = New-Object System.Drawing.Font($fontName, 14, [System.Drawing.FontStyle]::Bold) $fontReg = New-Object System.Drawing.Font($fontName, 14, [System.Drawing.FontStyle]::Regular) $brushWhite = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White) $brushGray = New-Object System.Drawing.SolidBrush([System.Drawing.ColorTranslator]::FromHtml("#C8D2D2")) # ----------------------------------------------------------------------- # Lines: text, font, brush # ----------------------------------------------------------------------- $texts = @( $hostname "Logged on user: $loggedUser" "OS: $osName" "CPU: $cpuCount at $cpuSpeed MHz RAM: $($ramGB)GB" "IPv4 address: $ips Machine domain: $domain" ) $fonts = @( $fontTitle, $fontReg, $fontBold, $fontReg, $fontReg ) $brushes = @( $brushWhite, $brushGray, $brushGray, $brushGray, $brushGray ) # ----------------------------------------------------------------------- # Measure total block height, then center vertically # ----------------------------------------------------------------------- $lineSpacing = 8 $heights = @() for ($i = 0; $i -lt $texts.Count; $i++) { $heights += [int]($g.MeasureString($texts[$i], $fonts[$i]).Height) } $totalH = ($heights | Measure-Object -Sum).Sum + $lineSpacing * ($texts.Count - 1) $currentY = [int](($height - $totalH) / 2) # ----------------------------------------------------------------------- # Draw each line centered horizontally # ----------------------------------------------------------------------- for ($i = 0; $i -lt $texts.Count; $i++) { $sz = $g.MeasureString($texts[$i], $fonts[$i]) $x = [int](($width - $sz.Width) / 2) $g.DrawString($texts[$i], $fonts[$i], $brushes[$i], [float]$x, [float]$currentY) $currentY += $heights[$i] + $lineSpacing } $g.Dispose() # ----------------------------------------------------------------------- # Save and set as wallpaper # ----------------------------------------------------------------------- $bmpPath = "C:\Windows\Setup\Scripts\desktopinfo.bmp" Write-Log "Saving BMP: $bmpPath" $bmp.Save($bmpPath, [System.Drawing.Imaging.ImageFormat]::Bmp) $bmp.Dispose() # Clear Windows wallpaper cache so it reloads from our BMP # Without this, Windows reuses TranscodedWallpaper and ignores the updated file $transcodedPath = "$env:APPDATA\Microsoft\Windows\Themes\TranscodedWallpaper" if (Test-Path $transcodedPath) { Remove-Item $transcodedPath -Force -ErrorAction SilentlyContinue Write-Log "Cleared TranscodedWallpaper cache" } # SPI_SETDESKTOPWALLPAPER=20, SPIF_UPDATEINIFILE|SPIF_SENDCHANGE=3 $result = [WallpaperApi]::SystemParametersInfo(20, 0, $bmpPath, 3) Write-Log "SystemParametersInfo result: $result" Write-Log "DesktopInfo render complete" -Level INFO '@ $renderContent | Set-Content -Path $RenderScript -Encoding UTF8 -Force Write-Log "Render script written" -Level OK # ----------------------------------------------------------------------- # Store deployment date in registry (used for reference) # ----------------------------------------------------------------------- Write-Log "Storing deployment date in registry" -Level INFO try { if (-not (Test-Path "HKLM:\SOFTWARE\X9\Deployment")) { New-Item -Path "HKLM:\SOFTWARE\X9\Deployment" -Force | Out-Null } $existingDate = (Get-ItemProperty -Path "HKLM:\SOFTWARE\X9\Deployment" ` -Name "DeployDate" -ErrorAction SilentlyContinue).DeployDate if (-not $existingDate) { Set-ItemProperty -Path "HKLM:\SOFTWARE\X9\Deployment" ` -Name "DeployDate" ` -Value (Get-Date -Format "yyyy-MM-dd") ` -Force Write-Log " DeployDate set: $(Get-Date -Format 'yyyy-MM-dd')" -Level OK } else { Write-Log " DeployDate already set: $existingDate" -Level INFO } } catch { Write-Log " Failed to set DeployDate: $_" -Level ERROR } # ----------------------------------------------------------------------- # Register scheduled task: DesktopInfo # Runs the render script on every user logon # ----------------------------------------------------------------------- Write-Log "Registering task: DesktopInfo" -Level STEP try { Unregister-ScheduledTask -TaskName "DesktopInfo" -Confirm:$false -ErrorAction SilentlyContinue $action = New-ScheduledTaskAction -Execute "powershell.exe" ` -Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$RenderScript`"" $trigger = New-ScheduledTaskTrigger -AtLogOn $trigger.Delay = "PT20S" # wait for network to be available $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 2) ` -MultipleInstances IgnoreNew ` -StartWhenAvailable $principal = New-ScheduledTaskPrincipal -GroupId "Users" -RunLevel Limited $task = New-ScheduledTask -Action $action ` -Trigger $trigger ` -Settings $settings ` -Principal $principal ` -Description "Render system info onto desktop wallpaper on logon" Register-ScheduledTask -TaskName "DesktopInfo" -InputObject $task -Force | Out-Null Write-Log "Task DesktopInfo registered" -Level OK } catch { Write-Log "Failed to register DesktopInfo task: $_" -Level ERROR } # ----------------------------------------------------------------------- # Run once immediately for current user # ----------------------------------------------------------------------- Write-Log "Running DesktopInfo render now for current user" -Level INFO try { & powershell.exe -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File $RenderScript Write-Log "DesktopInfo rendered" -Level OK } catch { Write-Log "DesktopInfo render failed: $_" -Level WARN } Write-Log "Step 7 complete" -Level OK