# 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
}

# Load site config + PC profile
. "$PSScriptRoot\lib\Get-PCProfile.ps1"

# ----------------------------------------------------------------------------
# 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
}

# Resolve startup tabs: profile > site-wide > hardcoded fallback
# Different PC types can have different tabs (e.g. Lab has Webmail
# instead of Plant Apps, Standard-Machine has Plant Apps).
$cfgTabs = Get-ProfileValue 'edgeStartupTabs'

$startupTabs = @()

if ($null -ne $cfgTabs -and $cfgTabs.Count -gt 0) {
    foreach ($tab in $cfgTabs) {
        $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 }
}

# Resolve homepage: profile can override (e.g. Lab has a different homepage
# than Standard). Falls back to the first startup tab if not specified.
$edgeHomepage = if ($pcProfile -and $pcProfile.edgeHomepage) { $pcProfile.edgeHomepage } else { $null }

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: profile override > first startup tab. Home button opens it, not NTP.
    $homepageUrl = if ($edgeHomepage) { $edgeHomepage } else { $startupTabs[0] }
    Write-Host "Homepage set to: $homepageUrl"
    Set-ItemProperty -Path $edgePolKey -Name 'HomepageLocation'     -Value $homepageUrl -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])"
}

# ============================================================================
# Chrome: same homepage + startup tabs as Edge
#
# The PPKG installs Chrome alongside Edge. Apply the same profile-driven
# homepage and startup tabs so both browsers behave identically. Uses the
# same $startupTabs and $homepageUrl resolved above.
# HKLM:\SOFTWARE\Policies\Google\Chrome mirrors the Edge policy structure.
# ============================================================================
Write-Host ""
Write-Host "Configuring Chrome startup tabs..."

$chromePath = @(
    'C:\Program Files\Google\Chrome\Application\chrome.exe',
    'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
) | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1

if (-not $chromePath) {
    Write-Host "  Chrome not installed - skipping." -ForegroundColor DarkGray
} elseif ($startupTabs.Count -eq 0) {
    Write-Host "  No startup tabs resolved - skipping Chrome config." -ForegroundColor DarkGray
} else {
    $chromePolKey = 'HKLM:\SOFTWARE\Policies\Google\Chrome'
    if (-not (Test-Path $chromePolKey)) {
        New-Item -Path $chromePolKey -Force | Out-Null
    }

    Set-ItemProperty -Path $chromePolKey -Name 'RestoreOnStartup' -Value 4 -Type DWord -Force

    $urlsKey = Join-Path $chromePolKey 'RestoreOnStartupURLs'
    if (Test-Path $urlsKey) {
        Remove-Item -Path $urlsKey -Recurse -Force
    }
    New-Item -Path $urlsKey -Force | Out-Null
    for ($i = 0; $i -lt $startupTabs.Count; $i++) {
        Set-ItemProperty -Path $urlsKey -Name ([string]($i + 1)) -Value $startupTabs[$i] -Type String -Force
    }

    $chromeHomepage = if ($homepageUrl) { $homepageUrl } elseif ($edgeHomepage) { $edgeHomepage } else { $startupTabs[0] }
    Set-ItemProperty -Path $chromePolKey -Name 'HomepageLocation'     -Value $chromeHomepage -Type String -Force
    Set-ItemProperty -Path $chromePolKey -Name 'HomepageIsNewTabPage' -Value 0 -Type DWord -Force
    Set-ItemProperty -Path $chromePolKey -Name 'ShowHomeButton'       -Value 1 -Type DWord -Force

    Write-Host "  Chrome startup tabs set ($($startupTabs.Count) tab(s)), homepage: $chromeHomepage"
}

Write-Host ""
Write-Host "================================================================"
Write-Host "08-EdgeDefaultBrowser.ps1 complete."
Write-Host "Edge + Chrome homepage and startup tabs configured."
Write-Host "Machine-wide GPO - applies to all users on next browser launch."
Write-Host "================================================================"

exit 0
