# run-enrollment.ps1 # Installs GCCH enrollment provisioning package via Install-ProvisioningPackage # Called by FirstLogonCommands as SupportUser (admin) after imaging $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 "ERROR: No .ppkg found in C:\Enrollment\" exit 1 } Log "Package: $($ppkgFile.Name)" # --- Set computer name to E --- $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 --- Log "Installing provisioning package..." try { Install-ProvisioningPackage -PackagePath $ppkgFile.FullName -ForceInstall -QuietInstall Log "Provisioning package installed successfully." } catch { Log "ERROR: Install-ProvisioningPackage failed: $_" Log "Attempting fallback with Add-ProvisioningPackage..." try { Add-ProvisioningPackage -PackagePath $ppkgFile.FullName -ForceInstall -QuietInstall Log "Provisioning package added successfully (fallback)." } catch { Log "ERROR: Fallback also failed: $_" exit 1 } } # --- Wait for PPKG provisioning to finish --- # Install-ProvisioningPackage is async — it queues the provisioning engine # and returns immediately. The actual app installs (Chrome, Office, Tanium, # CyberArk, etc.) run in the background as BPRT steps. Each step writes a # Log.txt under C:\Logs\BPRT\\. "Remove Staging Locations" is # the LAST step — when its Log.txt exists, all provisioning is done. # We poll for that marker before writing the stage file, so the PPKG reboot # doesn't fire while installs are still in progress. $bprtMarker = 'C:\Logs\BPRT\Remove Staging Locations\Log.txt' $maxWait = 900 # 15 minutes (Office install can be slow) $pollInterval = 10 $elapsed = 0 Log "Waiting for PPKG provisioning to complete (polling for $bprtMarker)..." while (-not (Test-Path -LiteralPath $bprtMarker) -and $elapsed -lt $maxWait) { Start-Sleep -Seconds $pollInterval $elapsed += $pollInterval # Show progress every 30 seconds if ($elapsed % 30 -eq 0) { $completedSteps = @(Get-ChildItem 'C:\Logs\BPRT' -Directory -ErrorAction SilentlyContinue | Where-Object { Test-Path (Join-Path $_.FullName 'Log.txt') } | Select-Object -ExpandProperty Name) Log " $elapsed s elapsed, $($completedSteps.Count) BPRT steps done: $($completedSteps -join ', ')" } } if (Test-Path -LiteralPath $bprtMarker) { Log "PPKG provisioning complete after $elapsed s." $allSteps = @(Get-ChildItem 'C:\Logs\BPRT' -Directory -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name) Log " Completed steps: $($allSteps -join ', ')" } else { Log "WARNING: PPKG provisioning timeout after $maxWait s — some apps may not be installed." Log " Proceeding anyway. The SYSTEM logon task will retry incomplete items on next boot." } # --- Set OOBE complete --- 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 # --- Stage the imaging chain for next boot --- # The PPKG schedules a reboot (PendingFileRenameOperations for Zscaler # rename, PPKG self-cleanup, etc). Instead of canceling it and cramming # Run-ShopfloorSetup into this same session, we let the reboot happen # and register a RunOnce entry that fires Stage-Dispatcher.ps1 on the # next autologon. The dispatcher reads setup-stage.txt and chains # through: shopfloor-setup -> sync-intune -> configure-pc. $stageFile = 'C:\Enrollment\setup-stage.txt' $dispatcherPath = 'C:\Enrollment\Stage-Dispatcher.ps1' $runOnceKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce' Log "Writing stage file: shopfloor-setup" Set-Content -LiteralPath $stageFile -Value 'shopfloor-setup' -Force if (Test-Path -LiteralPath $dispatcherPath) { Log "Registering RunOnce for Stage-Dispatcher.ps1" Set-ItemProperty -Path $runOnceKey -Name 'ShopfloorSetup' ` -Value "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"$dispatcherPath`"" ` -Type String -Force } else { Log "WARNING: Stage-Dispatcher.ps1 not found at $dispatcherPath - RunOnce not set" } Log "=== Enrollment complete. PPKG reboot will fire and Stage-Dispatcher picks up on next logon. ==="