# run-enrollment.ps1
# Installs GCCH enrollment provisioning package. That's it.
#
# Install-ProvisioningPackage triggers an immediate reboot -- nothing after
# that call executes. The sync_intune task and all other post-enrollment
# setup are registered by Run-ShopfloorSetup.ps1 BEFORE calling this script.

$ErrorActionPreference = 'Continue'
$logFile = "C:\Logs\enrollment.log"
New-Item -ItemType Directory -Path "C:\Logs" -Force -ErrorAction SilentlyContinue | Out-Null

function Log {
    param([string]$Message)
    $ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $line = "$ts  $Message"
    Write-Host $line
    Add-Content -Path $logFile -Value $line
}

Log "=== GE Aerospace GCCH Enrollment ==="

# --- Find the .ppkg ---
$ppkgFile = Get-ChildItem "C:\Enrollment\*.ppkg" -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $ppkgFile) {
    Log "No .ppkg found in C:\Enrollment\ - skipping enrollment."
    return
}
Log "Package: $($ppkgFile.Name)"

# --- Set computer name to E<serial> ---
$serial = (Get-CimInstance Win32_BIOS).SerialNumber
$newName = "E$serial"
Log "Setting computer name to $newName"
Rename-Computer -NewName $newName -Force -ErrorAction SilentlyContinue

# --- Install provisioning package ---
# IMPORTANT: The PPKG must be installed BEFORE OOBEComplete is set. Bulk
# enrollment PPKGs are designed to run during OOBE; on Windows 11 22H2+ they
# can hang indefinitely if OOBE is already marked complete.
#
# We invoke provtool.exe directly instead of Install-ProvisioningPackage.
# The PowerShell cmdlet enforces a hardcoded 180-second timeout on the
# underlying provtool call, which a 7-8 GB GCCH PPKG often exceeds on
# slower disks. When the cmdlet times out it throws, and the Add-
# ProvisioningPackage fallback has been observed to invoke provtool with
# an empty packagePathsToAdd (session registered but never started),
# leaving the PC un-enrolled. provtool.exe directly has no caller-side
# timeout; Start-Process -Wait waits on the actual child process.
#
# The PPKG triggers an IMMEDIATE reboot once fully applied. Nothing below
# that point executes on the current boot. BPRT app installs (Chrome,
# Office, Tanium, etc.) happen on the next boot. The sync_intune
# scheduled task (registered by Run-ShopfloorSetup.ps1 before calling us)
# fires at the next logon to monitor Intune enrollment.
$ppkgLogDir = "C:\Logs\PPKG"
New-Item -ItemType Directory -Path $ppkgLogDir -Force -ErrorAction SilentlyContinue | Out-Null
$provtool = Join-Path $env:SystemRoot 'System32\provtool.exe'
# Arg order matches what the Install-ProvisioningPackage cmdlet invokes
# internally (observed in ProvEventLog.txt): positional path, then /quiet,
# then /source. No /log: or /ppkg: prefix - those are not valid provtool
# flags and caused 0x80004005 E_FAIL in the first test.
#
# /source PSCmdlet matches what Install-ProvisioningPackage invokes
# internally and is the correct post-OOBE context. BPRT was tried first
# and verified to stop after the first RestartRequired command (DotNet35):
# only 3 of 21 commands ran (PPKG Version Check, Lock Screen, DotNet35),
# leaving Office/Chrome/Tanium/Activate-Windows etc never executed
# because BPRT expects the OOBE runtime to own the reboot-and-resume
# loop, and there is no OOBE runtime here. PSCmdlet registers a
# RunOnce-style resume handler so the remaining commands continue after
# the reboot Run-ShopfloorSetup issues. Timeout concerns that previously
# motivated BPRT don't apply here because we invoke provtool.exe
# directly, not via the 180s-capped Install-ProvisioningPackage cmdlet.
$provArgs = @("`"$($ppkgFile.FullName)`"", "/quiet", "/source", "PSCmdlet")

# Enable the Provisioning-Diagnostics-Provider Admin channel so events
# from the BPRT run land somewhere we can export afterward. This is
# idempotent - running each time is safe.
wevtutil.exe set-log 'Microsoft-Windows-Provisioning-Diagnostics-Provider/Admin' /enabled:true 2>$null | Out-Null
Log "Installing provisioning package via provtool.exe (no PowerShell timeout)..."
Log "Command: $provtool $($provArgs -join ' ')"
Log "PPKG diagnostic logs -> $ppkgLogDir (provtool writes them automatically)"
try {
    $p = Start-Process -FilePath $provtool -ArgumentList $provArgs -Wait -PassThru -NoNewWindow -ErrorAction Stop
    Log "provtool.exe exit code: $($p.ExitCode)"
    if ($p.ExitCode -ne 0) {
        $hex = '0x{0:X8}' -f $p.ExitCode
        Log "WARNING: provtool.exe returned non-zero exit code ($hex). Check $ppkgLogDir for diagnostic bundle."
    }
} catch {
    Log "ERROR: Failed to launch provtool.exe: $_"
}

# --- Harvest Windows' own provisioning diagnostics into $ppkgLogDir ---
# provtool.exe /quiet does not drop a zip bundle on success, so the real
# detail lives under C:\ProgramData\Microsoft\Provisioning\, in the
# registry under HKLM\Software\Microsoft\Provisioning\Sessions\*, and in
# the Provisioning-Diagnostics-Provider event log. Copy/export all three
# into our log dir so they ride back with the shopfloor logs bundle.
Log "Harvesting Windows provisioning diagnostics to $ppkgLogDir..."
try {
    $provData = 'C:\ProgramData\Microsoft\Provisioning'
    if (Test-Path $provData) {
        Copy-Item -Path (Join-Path $provData '*') -Destination $ppkgLogDir `
                  -Recurse -Force -ErrorAction SilentlyContinue
        Log "  copied $provData -> $ppkgLogDir"
    } else {
        Log "  $provData not present (provtool may not have touched it)"
    }
} catch {
    Log "  WARN: ProgramData copy threw: $_"
}

try {
    $sessions = Get-ChildItem 'HKLM:\Software\Microsoft\Provisioning\Sessions' -ErrorAction SilentlyContinue
    if ($sessions) {
        $snap = $sessions | ForEach-Object {
            $props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
            if ($props) {
                [pscustomobject]@{
                    Session      = $_.PSChildName
                    BeginTime    = $props.BeginTime
                    LastRunTime  = $props.LastRunTime
                    RebootCount  = $props.RebootCount
                    State        = $props.State
                    StateValue   = $props.StateValue
                }
            }
        }
        $snap | ConvertTo-Json -Depth 3 |
            Out-File -FilePath (Join-Path $ppkgLogDir 'provisioning-sessions.json') -Encoding UTF8
        Log "  wrote provisioning-sessions.json ($($snap.Count) session(s))"
        foreach ($s in $snap) {
            Log "    session $($s.Session): State=$($s.State) RebootCount=$($s.RebootCount)"
        }
    } else {
        Log "  no sessions under HKLM:\Software\Microsoft\Provisioning\Sessions"
    }
} catch {
    Log "  WARN: session snapshot threw: $_"
}

try {
    $evtx = Join-Path $ppkgLogDir 'Provisioning-Diagnostics-Admin.evtx'
    if (Test-Path $evtx) { Remove-Item $evtx -Force -ErrorAction SilentlyContinue }
    $null = & wevtutil.exe epl 'Microsoft-Windows-Provisioning-Diagnostics-Provider/Admin' $evtx 2>&1
    if (Test-Path $evtx) { Log "  exported $evtx" }
} catch {
    Log "  WARN: wevtutil export threw: $_"
}

# --- Set OOBE complete (only reached if PPKG didn't trigger immediate reboot) ---
Log "Setting OOBE as complete..."
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OOBE" /v OOBEComplete /t REG_DWORD /d 1 /f | Out-Null
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OOBE" /v SetupDisplayedEula /t REG_DWORD /d 1 /f | Out-Null

# If we get here, the PPKG didn't reboot immediately. Unlikely but handle it.
Log "PPKG did not trigger immediate reboot. Returning to caller."
