# 07-TaskbarLayout.ps1 - Minimal taskbar pinner. # # Reads the shortcuts that 06-OrganizeDesktop.ps1 created in # C:\Users\Public\Desktop\Shopfloor Tools\ and writes a LayoutModification.xml # that pins them to the taskbar along with Microsoft Edge. # # This script does NOT create, move, or copy any shortcuts - all shortcut # management lives in 06. 07 is the last-mile taskbar config only. # # Pin order (left to right): Edge, WJ Shopfloor, UDC, eDNC, NTLARS, Defect_Tracker. # # LayoutModification.xml is written to the Default User profile shell # directory, which means the pins apply on FIRST LOGON of any new user # profile. Existing profiles don't re-read the Default User template, so # they won't pick up the pins without a manual re-pin or profile delete. # This is a Windows design limitation - syspin.exe style hacks are the # only workaround for existing profiles, and they're unsupported. $ErrorActionPreference = 'Continue' # ============================================================================ # Admin check - writing to the Default User profile requires elevation. # ============================================================================ $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $isAdmin) { Write-Host "" Write-Host "ERROR: 07-TaskbarLayout.ps1 must run as Administrator." -ForegroundColor Red Write-Host " Re-run from an elevated PowerShell." -ForegroundColor Red Write-Host "" exit 1 } $publicDesktop = 'C:\Users\Public\Desktop' $shopfloorToolsDir = Join-Path $publicDesktop 'Shopfloor Tools' $defaultUserShell = 'C:\Users\Default\AppData\Local\Microsoft\Windows\Shell' $layoutXmlPath = Join-Path $defaultUserShell 'LayoutModification.xml' # ============================================================================ # Pin list: exact ordered list of shortcut names to pin. Each entry points # at a .lnk file via a Windows environment-variable-expanded path. Edge is # special-cased to its default Start Menu location since Windows maintains # it; all other entries reference C:\Users\Public\Desktop\Shopfloor Tools\ # which 06-OrganizeDesktop.ps1 populates. # ============================================================================ $pinSpec = @( @{ Name = 'Microsoft Edge' Path = '%ALLUSERSPROFILE%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk' # Resolved literal path used to check existence (can't Test-Path an # unexpanded env var reliably on older PS versions) Literal = 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk' } @{ Name = 'WJ Shopfloor' Path = '%PUBLIC%\Desktop\Shopfloor Tools\WJ Shopfloor.lnk' Literal = (Join-Path $shopfloorToolsDir 'WJ Shopfloor.lnk') } @{ Name = 'UDC' Path = '%PUBLIC%\Desktop\Shopfloor Tools\UDC.lnk' Literal = (Join-Path $shopfloorToolsDir 'UDC.lnk') } @{ Name = 'eDNC' Path = '%PUBLIC%\Desktop\Shopfloor Tools\eDNC.lnk' Literal = (Join-Path $shopfloorToolsDir 'eDNC.lnk') } @{ Name = 'NTLARS' Path = '%PUBLIC%\Desktop\Shopfloor Tools\NTLARS.lnk' Literal = (Join-Path $shopfloorToolsDir 'NTLARS.lnk') } @{ Name = 'Defect_Tracker' Path = '%PUBLIC%\Desktop\Shopfloor Tools\Defect_Tracker.lnk' Literal = (Join-Path $shopfloorToolsDir 'Defect_Tracker.lnk') } ) # ============================================================================ # Build the pin list - skip any whose .lnk is missing # ============================================================================ Write-Host "" Write-Host "Checking which Shopfloor Tools shortcuts exist..." $pinPaths = @() foreach ($pin in $pinSpec) { if (Test-Path -LiteralPath $pin.Literal) { Write-Host " pin: $($pin.Name) -> $($pin.Literal)" $pinPaths += $pin.Path } else { Write-Host " skip: $($pin.Name) - not found at $($pin.Literal)" -ForegroundColor DarkGray } } if ($pinPaths.Count -eq 0) { Write-Warning "No pins to apply (nothing found in Shopfloor Tools\). Did 06-OrganizeDesktop.ps1 run first?" exit 0 } # ============================================================================ # Write LayoutModification.xml # ============================================================================ $pinXml = ($pinPaths | ForEach-Object { " " }) -join "`r`n" $layoutXml = @" $pinXml "@ try { if (-not (Test-Path -LiteralPath $defaultUserShell)) { New-Item -ItemType Directory -Path $defaultUserShell -Force -ErrorAction Stop | Out-Null } # -ErrorAction Stop so Access Denied becomes a catchable terminating error # instead of silently falling through to the success message. Set-Content -LiteralPath $layoutXmlPath -Value $layoutXml -Encoding UTF8 -Force -ErrorAction Stop Write-Host "" Write-Host "Wrote taskbar layout with $($pinPaths.Count) pin(s) to:" Write-Host " $layoutXmlPath" Write-Host "" Write-Host "Pins will apply on first logon of any NEW user profile." } catch { Write-Warning "Failed to write $layoutXmlPath : $_" exit 1 } exit 0