Three new baseline scripts that run during shopfloor imaging to clean up
the end-user Public Desktop. Before this, Azure AD users logged into a
shopfloor PC and saw 20+ loose shortcuts at the desktop root (Office
apps, OpenText sessions, WJ web portals, DNC utilities, Defect Tracker,
plus .url files for every intranet page) with no organization. End users
couldn't find anything.
06-OrganizeDesktop.ps1 - Single source of truth for Public Desktop layout
Phase 1: sweeps loose shortcuts at the desktop root into three category
folders - Office\, Shopfloor Tools\, Web Links\ - by filename regex,
extension, and .lnk target resolution. Allowlists eDNC.lnk and
NTLARS.lnk to stay at root since end users click them too often.
Unknown items are left at the root on purpose (never delete).
Phase 2: materializes specific app shortcuts into Shopfloor Tools\.
UDC / eDNC / NTLARS are built fresh from their .exe paths; WJ
Shopfloor and Defect_Tracker are MSI-advertised (empty TargetPath,
Darwin descriptor) so we copy the existing .lnk from wherever it
lives via a multi-location lookup. Each entry is conditional on its
source being present - script runs cleanly on PC types without DnC.
Phase 3: drops eDNC.lnk and NTLARS.lnk at desktop root from the
Shopfloor Tools\ copies, so end users have both a folder version
and a quick-access root version.
Phase 4: registers an "Organize Public Desktop" scheduled task that
re-runs phase 1 at every logon. Shortcuts added later by DSC /
Intune / msiexec get filed automatically without another imaging
pass. Admin check at the top, -ErrorAction Stop on Register-
ScheduledTask and directory creation so failures are caught
instead of printing false success.
07-TaskbarLayout.ps1 - Minimal taskbar pinner
Checks which .lnk files 06 created in Shopfloor Tools\, then writes
LayoutModification.xml to the Default User profile with taskbar pins
in order: Edge, WJ Shopfloor, UDC, eDNC, Defect_Tracker. No shortcut
creation in this script - all shortcut management lives in 06.
Missing .lnks are skipped (PC types without DnC just get fewer pins).
Applies on first logon of new user profiles (Azure AD users after
enrollment). Existing profiles don't re-read Default User - Windows
design limitation since 1703, no programmatic fix.
08-EdgeDefaultBrowser.ps1 - Edge as default browser + startup tabs
Motivated by the ppkg installing Chrome alongside Edge: new Azure AD
users hit a "Choose your default app" picker on first URL click
because nothing is marked default. Two layers:
1. dism /Online /Import-DefaultAppAssociations:<xml> writes an XML
with Edge ProgIds for http/https/.htm/.html/.pdf/.svg/.webp into
the Default User profile template. New profiles inherit.
2. HKLM:\SOFTWARE\Policies\Microsoft\Windows\System\
DefaultAssociationsConfiguration registry value (the "Set a
default associations configuration file" GPO) points at the same
XML so Windows re-applies on every logon, catching Windows-update
defaults-reset cases.
Leaves Chrome installed, just not the default URL handler.
Also sets Edge startup tabs via machine-wide policies under
HKLM:\SOFTWARE\Policies\Microsoft\Edge:
RestoreOnStartup = 4 (open specific URLs)
RestoreOnStartupURLs = Plant Apps, WJ Shop Floor Homepage, Shopfloor
Dashboard (tab order per spec)
HomepageLocation = first tab (Plant Apps)
HomepageIsNewTabPage = 0
ShowHomeButton = 1
URLs are resolved dynamically from the .url files on the Public
Desktop (or Web Links\ after the sweep), so if WJDT changes a URL
later the script picks it up without a code change. Fallbacks are
hardcoded for the two portals we have URLs memorized for; Plant Apps
has no fallback and will be skipped if the .url file is missing.
Test workflow: admin-check in all three scripts fails fast on non-
elevated runs instead of spamming half-successful Access Denied output
like the first draft did.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
141 lines
5.8 KiB
PowerShell
141 lines
5.8 KiB
PowerShell
# 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, Defect_Tracker.
|
|
# NTLARS is intentionally not pinned - per the original spec it lives on
|
|
# the desktop root only.
|
|
#
|
|
# 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 = '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 {
|
|
" <taskbar:DesktopApp DesktopApplicationLinkPath=`"$_`"/>"
|
|
}) -join "`r`n"
|
|
|
|
$layoutXml = @"
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<LayoutModificationTemplate
|
|
xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
|
|
xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"
|
|
xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"
|
|
xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"
|
|
Version="1">
|
|
<CustomTaskbarLayoutCollection PinListPlacement="Replace">
|
|
<defaultlayout:TaskbarLayout>
|
|
<taskbar:TaskbarPinList>
|
|
$pinXml
|
|
</taskbar:TaskbarPinList>
|
|
</defaultlayout:TaskbarLayout>
|
|
</CustomTaskbarLayoutCollection>
|
|
</LayoutModificationTemplate>
|
|
"@
|
|
|
|
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
|