New site-config.json file at C:\Enrollment\ (staged by startnet.cmd from
the enrollment share) contains all West Jefferson-specific values that were
previously hardcoded across 7 scripts. To deploy at a different GE site,
clone site-config.json and change the values - scripts need zero changes.
Config schema (v1.0):
siteName / siteNameCompact - UDC/eDNC site args
urls{} - Edge startup tab fallback URLs
edgeStartupTabs[] - ordered tab list with .url file basenames
opentext{} - excluded .hep profiles and .lnk shortcuts
startupItems[] - Configure-PC toggle list (exe/existing/url)
taskbarPins[] - 07-TaskbarLayout pin order with lnk paths
desktopApps[] - 06-OrganizeDesktop Phase 2 app list
Every script uses the same inline Get-SiteConfig helper that reads the
JSON and returns $null if missing/corrupt. All consumers fall back to the
current hardcoded West Jefferson defaults when $siteConfig is null, so
PXE servers without a site-config.json continue working identically.
Scripts updated:
06-OrganizeDesktop.ps1 - desktopApps array from config
07-TaskbarLayout.ps1 - pinSpec array from config
08-EdgeDefaultBrowser.ps1 - startup tab loop from config
Configure-PC.ps1 - startup items + site name from config
Check-MachineNumber.ps1 - site name from config
Set-MachineNumber.ps1 - site name from config
01-eDNC.ps1 - siteName + siteNameCompact from config
startnet.cmd - copies site-config.json from enrollment share
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
278 lines
13 KiB
PowerShell
278 lines
13 KiB
PowerShell
# 08-EdgeDefaultBrowser.ps1 - Set Microsoft Edge as the default browser
|
|
# and PDF handler for all new user profiles, and configure startup tabs
|
|
# so Edge opens with Plant Apps / Shop Floor Homepage / Shopfloor Dashboard
|
|
# when the end user first launches it.
|
|
#
|
|
# WHY THIS EXISTS:
|
|
# The West Jefferson shopfloor ppkg installs Google Chrome alongside Edge.
|
|
# On first URL click in a new Azure AD user profile, Windows pops a "Choose
|
|
# your default app" picker because multiple browsers are installed and
|
|
# nothing has been marked as default. End users hit this on every fresh PC
|
|
# and it derails the shopfloor workflow.
|
|
#
|
|
# HOW IT WORKS:
|
|
# Two layers, belt-and-suspenders:
|
|
#
|
|
# 1. DISM default-app-associations XML
|
|
# Writes an XML file mapping http/https/.htm/.html/.pdf/.svg/etc to
|
|
# Edge's ProgIds, then runs:
|
|
# dism /Online /Import-DefaultAppAssociations:<xml>
|
|
# This imports the XML into the Default User profile template. Any
|
|
# NEW user profile created after this point inherits the associations
|
|
# on first logon. Microsoft-supported, works across Win10/Win11.
|
|
#
|
|
# 2. Group Policy registry key
|
|
# HKLM:\SOFTWARE\Policies\Microsoft\Windows\System\DefaultAssociationsConfiguration
|
|
# points at the same XML file. This is the "Set a default associations
|
|
# configuration file" GPO. With this set, Windows re-applies the XML
|
|
# on every logon, not just once at profile creation - so Windows
|
|
# update defaults-reset and similar edge cases don't un-do us.
|
|
#
|
|
# CAVEATS:
|
|
# - Applies to NEW profiles on first logon. An existing profile that's
|
|
# already been logged in (e.g. SupportUser) won't pick up the change
|
|
# without a manual Settings > Default apps visit. Acceptable because
|
|
# SupportUser isn't the end-user account.
|
|
# - Does not UNinstall Chrome. Chrome remains available, it's just not
|
|
# the default handler for URLs.
|
|
# - Microsoft blocks programmatic UserChoice hash tampering since Win10
|
|
# 1703. The DISM + policy route is the only supported path, and it
|
|
# only fires for new profiles - that's by design.
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Admin check
|
|
# ----------------------------------------------------------------------------
|
|
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
if (-not $isAdmin) {
|
|
Write-Host ""
|
|
Write-Host "ERROR: 08-EdgeDefaultBrowser.ps1 must run as Administrator." -ForegroundColor Red
|
|
Write-Host " Re-run from an elevated PowerShell." -ForegroundColor Red
|
|
Write-Host ""
|
|
exit 1
|
|
}
|
|
|
|
function Get-SiteConfig {
|
|
$configPath = 'C:\Enrollment\site-config.json'
|
|
if (-not (Test-Path -LiteralPath $configPath)) {
|
|
Write-Host "site-config.json not found - using defaults" -ForegroundColor DarkGray
|
|
return $null
|
|
}
|
|
try {
|
|
return (Get-Content -LiteralPath $configPath -Raw -ErrorAction Stop | ConvertFrom-Json)
|
|
} catch {
|
|
Write-Warning "Failed to parse site-config.json: $_"
|
|
return $null
|
|
}
|
|
}
|
|
$siteConfig = Get-SiteConfig
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Sanity: Edge must be installed for this to mean anything
|
|
# ----------------------------------------------------------------------------
|
|
$edgeCandidates = @(
|
|
'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe',
|
|
'C:\Program Files\Microsoft\Edge\Application\msedge.exe'
|
|
)
|
|
$edgePath = $edgeCandidates | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1
|
|
if (-not $edgePath) {
|
|
Write-Host "Microsoft Edge not found in either Program Files location - skipping default browser config."
|
|
exit 0
|
|
}
|
|
Write-Host "Found Edge at: $edgePath"
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# XML: Edge as default for web browsing + PDFs + common image formats
|
|
# ----------------------------------------------------------------------------
|
|
$xml = @'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<DefaultAssociations>
|
|
<Association Identifier=".htm" ProgId="MSEdgeHTM" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier=".html" ProgId="MSEdgeHTM" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier=".mht" ProgId="MSEdgeMHT" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier=".mhtml" ProgId="MSEdgeMHT" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier=".pdf" ProgId="MSEdgePDF" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier=".svg" ProgId="MSEdgeSVG" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier=".webp" ProgId="MSEdgeHTM" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier="http" ProgId="MSEdgeHTM" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier="https" ProgId="MSEdgeHTM" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier="ftp" ProgId="MSEdgeHTM" ApplicationName="Microsoft Edge" />
|
|
<Association Identifier="microsoft-edge" ProgId="MSEdgeHTM" ApplicationName="Microsoft Edge" />
|
|
</DefaultAssociations>
|
|
'@
|
|
|
|
# Write to a stable location that persists across reimaging (C:\Enrollment is
|
|
# the canonical staging dir in this repo, survives logoff/logon, referenced
|
|
# by the GP policy below so it must be a path every user-session can read).
|
|
$xmlDir = 'C:\Enrollment'
|
|
$xmlPath = Join-Path $xmlDir 'edge-default-associations.xml'
|
|
|
|
if (-not (Test-Path -LiteralPath $xmlDir)) {
|
|
New-Item -ItemType Directory -Path $xmlDir -Force | Out-Null
|
|
}
|
|
Set-Content -LiteralPath $xmlPath -Value $xml -Encoding UTF8 -Force
|
|
Write-Host "Wrote associations XML to: $xmlPath"
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Layer 1: DISM import into the Default User profile template
|
|
# ----------------------------------------------------------------------------
|
|
Write-Host ""
|
|
Write-Host "Layer 1: dism /Online /Import-DefaultAppAssociations..."
|
|
& dism.exe /Online /Import-DefaultAppAssociations:"$xmlPath" | Out-Null
|
|
$dismExit = $LASTEXITCODE
|
|
if ($dismExit -eq 0) {
|
|
Write-Host " OK - defaults imported into Default User template."
|
|
} else {
|
|
Write-Warning " dism returned exit code $dismExit - import may not have applied."
|
|
}
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Layer 2: Group Policy registry key - enforces XML on every logon
|
|
# ----------------------------------------------------------------------------
|
|
Write-Host ""
|
|
Write-Host "Layer 2: Setting DefaultAssociationsConfiguration policy..."
|
|
$polKey = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\System'
|
|
if (-not (Test-Path $polKey)) {
|
|
New-Item -Path $polKey -Force | Out-Null
|
|
}
|
|
Set-ItemProperty -Path $polKey -Name 'DefaultAssociationsConfiguration' -Value $xmlPath -Type String -Force
|
|
Write-Host " OK - HKLM:\SOFTWARE\Policies\Microsoft\Windows\System\DefaultAssociationsConfiguration = $xmlPath"
|
|
|
|
Write-Host ""
|
|
Write-Host "================================================================"
|
|
Write-Host "Edge default browser config applied."
|
|
Write-Host "================================================================"
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Edge startup tabs + homepage
|
|
#
|
|
# End users should see Plant Apps, the Shop Floor Homepage, and the
|
|
# Shopfloor Dashboard open in three tabs the moment Edge launches. Rather
|
|
# than hardcoding URLs in this script, we read them out of the .url files
|
|
# that already live on the Public Desktop (copied there by ppkg). This
|
|
# way, if an admin renames or retargets a .url file later, the script
|
|
# picks up the new URL on the next imaging run without a code change.
|
|
#
|
|
# Fallback: if the .url file is missing, we fall back to a hardcoded URL
|
|
# (only for the ones we know for sure). Plant Apps has no fallback because
|
|
# I don't have its URL memorized.
|
|
#
|
|
# Machine policies (all under HKLM:\SOFTWARE\Policies\Microsoft\Edge):
|
|
# RestoreOnStartup = 4 (open a specific set of URLs)
|
|
# RestoreOnStartupURLs = subkey with "1","2","3"... = URLs in tab order
|
|
# HomepageLocation = first startup URL (home button opens same)
|
|
# HomepageIsNewTabPage = 0 (home button opens HomepageLocation, not NTP)
|
|
# ShowHomeButton = 1 (show the home button in the toolbar)
|
|
# ----------------------------------------------------------------------------
|
|
Write-Host ""
|
|
Write-Host "Configuring Edge startup tabs..."
|
|
|
|
function Get-UrlFromFile {
|
|
param([string]$Path)
|
|
try {
|
|
$content = Get-Content -LiteralPath $Path -ErrorAction Stop
|
|
$urlLine = $content | Where-Object { $_ -match '^URL=' } | Select-Object -First 1
|
|
if ($urlLine) {
|
|
return ($urlLine -replace '^URL=', '').Trim()
|
|
}
|
|
} catch {}
|
|
return $null
|
|
}
|
|
|
|
function Resolve-StartupUrl {
|
|
param(
|
|
[string]$BaseName, # .url filename without extension
|
|
[string]$Fallback = ''
|
|
)
|
|
# Look in Public Desktop root first, then Web Links subfolder (06's
|
|
# sweeper may have moved it there already).
|
|
$candidates = @(
|
|
"C:\Users\Public\Desktop\$BaseName.url",
|
|
"C:\Users\Public\Desktop\Web Links\$BaseName.url"
|
|
)
|
|
foreach ($c in $candidates) {
|
|
if (Test-Path -LiteralPath $c) {
|
|
$url = Get-UrlFromFile $c
|
|
if ($url) {
|
|
Write-Host " resolved $BaseName -> $url (from $c)"
|
|
return $url
|
|
}
|
|
}
|
|
}
|
|
if ($Fallback) {
|
|
Write-Host " fallback $BaseName -> $Fallback (.url file not found)" -ForegroundColor DarkGray
|
|
return $Fallback
|
|
}
|
|
Write-Warning " $BaseName : no .url file found and no fallback - will be skipped"
|
|
return $null
|
|
}
|
|
|
|
# Tab order as requested: Plant Apps, Shop Floor Homepage, Shopfloor Dashboard
|
|
$startupTabs = @()
|
|
|
|
if ($siteConfig -and $siteConfig.edgeStartupTabs) {
|
|
foreach ($tab in $siteConfig.edgeStartupTabs) {
|
|
$fallback = if ($tab.fallbackUrlKey -and $siteConfig.urls) { $siteConfig.urls.$($tab.fallbackUrlKey) } else { '' }
|
|
$url = Resolve-StartupUrl -BaseName $tab.baseName -Fallback $fallback
|
|
if ($url) { $startupTabs += $url }
|
|
}
|
|
} else {
|
|
$plantApps = Resolve-StartupUrl -BaseName 'Plant Apps' -Fallback 'https://mes-wjefferson.apps.lr.geaerospace.net/run/?app_name=Plant%20Applications'
|
|
if ($plantApps) { $startupTabs += $plantApps }
|
|
|
|
$shopFloorHome = Resolve-StartupUrl -BaseName 'WJ Shop Floor Homepage' -Fallback 'http://tsgwp00524.logon.ds.ge.com/'
|
|
if ($shopFloorHome) { $startupTabs += $shopFloorHome }
|
|
|
|
$dashboard = Resolve-StartupUrl -BaseName 'Shopfloor Dashboard' -Fallback 'https://tsgwp00525.wjs.geaerospace.net/shopdb/shopfloor-dashboard/'
|
|
if ($dashboard) { $startupTabs += $dashboard }
|
|
}
|
|
|
|
if ($startupTabs.Count -eq 0) {
|
|
Write-Warning "No startup tab URLs resolved - skipping Edge startup config."
|
|
} else {
|
|
$edgePolKey = 'HKLM:\SOFTWARE\Policies\Microsoft\Edge'
|
|
if (-not (Test-Path $edgePolKey)) {
|
|
New-Item -Path $edgePolKey -Force | Out-Null
|
|
}
|
|
|
|
# RestoreOnStartup = 4 means "open a specific set of URLs" (the list
|
|
# lives under the RestoreOnStartupURLs subkey below).
|
|
Set-ItemProperty -Path $edgePolKey -Name 'RestoreOnStartup' -Value 4 -Type DWord -Force
|
|
|
|
# Build RestoreOnStartupURLs subkey: numbered string values "1","2","3"
|
|
$urlsKey = Join-Path $edgePolKey 'RestoreOnStartupURLs'
|
|
if (Test-Path $urlsKey) {
|
|
# Wipe any prior entries so we don't leak stale tabs if the list
|
|
# shrinks between runs
|
|
Remove-Item -Path $urlsKey -Recurse -Force
|
|
}
|
|
New-Item -Path $urlsKey -Force | Out-Null
|
|
for ($i = 0; $i -lt $startupTabs.Count; $i++) {
|
|
$name = [string]($i + 1)
|
|
Set-ItemProperty -Path $urlsKey -Name $name -Value $startupTabs[$i] -Type String -Force
|
|
}
|
|
|
|
# Homepage = the first startup tab. Home button opens it, not NTP.
|
|
Set-ItemProperty -Path $edgePolKey -Name 'HomepageLocation' -Value $startupTabs[0] -Type String -Force
|
|
Set-ItemProperty -Path $edgePolKey -Name 'HomepageIsNewTabPage' -Value 0 -Type DWord -Force
|
|
Set-ItemProperty -Path $edgePolKey -Name 'ShowHomeButton' -Value 1 -Type DWord -Force
|
|
|
|
Write-Host ""
|
|
Write-Host "Edge startup tabs set ($($startupTabs.Count) tab(s)):"
|
|
for ($i = 0; $i -lt $startupTabs.Count; $i++) {
|
|
Write-Host " $($i + 1). $($startupTabs[$i])"
|
|
}
|
|
Write-Host "Homepage set to: $($startupTabs[0])"
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "================================================================"
|
|
Write-Host "08-EdgeDefaultBrowser.ps1 complete."
|
|
Write-Host "Effective for new user profiles on first logon (Azure AD users)."
|
|
Write-Host "Existing profiles will pick up the startup-tab policy on next"
|
|
Write-Host "Edge launch - it's a machine-wide GPO."
|
|
Write-Host "================================================================"
|
|
|
|
exit 0
|