diff --git a/godbrain_core/reclaim11/README.md b/godbrain_core/reclaim11/README.md index d4f25e1..bfc8f3a 100644 --- a/godbrain_core/reclaim11/README.md +++ b/godbrain_core/reclaim11/README.md @@ -10,10 +10,12 @@ stay locked until a WinPE receipt. ## What to do -1. Get `Reclaim11-kit-v9.zip` from - [GitHub Releases](https://github.com/usrname1git/GodBrain/releases/tag/reclaim11-v9) +1. Get `Reclaim11-kit-v10.zip` from + [GitHub Releases](https://github.com/usrname1git/GodBrain/releases/tag/reclaim11-v10) and unzip it. Check the `.sha256` next to the zip. -2. Double-click `Reclaim11.cmd`. You do not type `pwsh`. +2. Double-click `Reclaim11.cmd`. You do not type `pwsh`. If you only have + Windows PowerShell 5.1, the GUI offers the official PowerShell 7 MSI + (adds PATH). WinPE stays 5.1. 3. Click **TEST FIRST** (noob door) or **TEST SELECTED** (expert). Nothing is deleted. Read the log. 4. Then pick a door: @@ -58,10 +60,10 @@ ADK + WinPE addon **10.1.26100.2454**, not ADK 28000. pwsh -NoProfile -File .\scripts\New-Reclaim11WinPeIso.ps1 ``` -Output: `C:\Reclaim11\Reclaim11-WinPE-v9.iso`. +Output: `C:\Reclaim11\Reclaim11-WinPE-v10.iso`. v1/v2 copied EXE over `.sys` and bootloop; do not attach those. -Snapshot, attach **v9**. PE **deletes** catalog +Snapshot, attach **v10**. PE **deletes** catalog `drivers\WdBoot.sys` / `WdFilter.sys` / `WdNisDrv.sys` / `WdDevFlt.sys` (exact names, never a `Wd*.sys` glob), stubs catalog usermode EXEs, `reg delete` pack-A keys then Start=4 fallback, IFEO + diff --git a/godbrain_core/reclaim11/catalog.json b/godbrain_core/reclaim11/catalog.json index 5f83735..95c01b8 100644 --- a/godbrain_core/reclaim11/catalog.json +++ b/godbrain_core/reclaim11/catalog.json @@ -1,6 +1,6 @@ { "id": "reclaim11-pack-a-v1", - "kit_version": "9", + "kit_version": "10", "pack": "A", "trust": "candidate", "auto_verify": "never", diff --git a/godbrain_core/reclaim11/ps1/Reclaim11.ps1 b/godbrain_core/reclaim11/ps1/Reclaim11.ps1 index 8e4e1a1..7762cd0 100644 --- a/godbrain_core/reclaim11/ps1/Reclaim11.ps1 +++ b/godbrain_core/reclaim11/ps1/Reclaim11.ps1 @@ -25,6 +25,7 @@ $here = Get-Reclaim11Root . (Join-Path $ps1Dir "telemetry_cleanse.ps1") . (Join-Path $ps1Dir "nic_tune.ps1") . (Join-Path $ps1Dir "latency_bake.ps1") +. (Join-Path $ps1Dir "install_pwsh.ps1") function Write-Reclaim11InventoryFile { param($Inventory, [string]$Path) @@ -100,6 +101,18 @@ if ($sta -ne "STA" -or -not $admin) { return } +if ($PSVersionTable.PSVersion.Major -lt 7) { + $pwsh7 = Show-Reclaim11PwshOffer + if ($pwsh7) { + $arg = @( + "-STA", "-NoProfile", "-WindowStyle", "Hidden", "-ExecutionPolicy", "Bypass", "-File", $MyInvocation.MyCommand.Path + ) + if ($WinPeLog) { $arg += @("-WinPeLog", $WinPeLog) } + Start-Process -FilePath $pwsh7 -ArgumentList $arg -WindowStyle Hidden + return + } +} + try { $Host.UI.RawUI.WindowTitle = "Reclaim11" } catch { } $logRoot = [Environment]::GetFolderPath("LocalApplicationData") @@ -590,15 +603,15 @@ $btnPrep.Add_Click({ return } $isoDir = "C:\Reclaim11" - $want = Join-Path $isoDir "Reclaim11-WinPE-v9.iso" + $want = Join-Path $isoDir "Reclaim11-WinPE-v10.iso" $iso = $want - foreach ($n in @("Reclaim11-WinPE-v9.iso", "Reclaim11-WinPE.iso", "Reclaim11-WinPE-v8.iso", "Reclaim11-WinPE-v7.iso")) { + foreach ($n in @("Reclaim11-WinPE-v10.iso", "Reclaim11-WinPE-v9.iso", "Reclaim11-WinPE.iso", "Reclaim11-WinPE-v8.iso", "Reclaim11-WinPE-v7.iso")) { $p = Join-Path $isoDir $n if (Test-Path -LiteralPath $p) { $iso = $p; break } } $have = Test-Path -LiteralPath $iso $ask = if ($have) { - "ISO already at:`n$iso`n`nRebuild v9 to:`n$want`n`nNeeds ADK + WinPE addon 10.1.26100.2454 (not 28000). Several minutes. DISM only against the WinPE image, not this Windows." + "ISO already at:`n$iso`n`nRebuild v10 to:`n$want`n`nNeeds ADK + WinPE addon 10.1.26100.2454 (not 28000). Several minutes. DISM only against the WinPE image, not this Windows." } else { "Build WinPE ISO to:`n$want`n`nNeeds ADK + WinPE addon 10.1.26100.2454 (not 28000). Several minutes. DISM only against the WinPE image, not this Windows." } diff --git a/godbrain_core/reclaim11/ps1/install_pwsh.ps1 b/godbrain_core/reclaim11/ps1/install_pwsh.ps1 new file mode 100644 index 0000000..3205bb5 --- /dev/null +++ b/godbrain_core/reclaim11/ps1/install_pwsh.ps1 @@ -0,0 +1,85 @@ +# Offer official PowerShell 7 MSI when the GUI started on 5.1. +# GitHub MSI + msiexec ADD_PATH. Never irm|iex, never the Store stub. + +function Get-Reclaim11PwshMsiAsset { + $arch = [string]$env:PROCESSOR_ARCHITECTURE + $tag = "win-x64.msi" + if ($arch -eq "ARM64") { $tag = "win-arm64.msi" } + try { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } catch { } + $wc = New-Object System.Net.WebClient + $wc.Headers.Add("User-Agent", "Reclaim11") + $wc.Headers.Add("Accept", "application/vnd.github+json") + $raw = $wc.DownloadString("https://api.github.com/repos/PowerShell/PowerShell/releases/latest") + $rel = $raw | ConvertFrom-Json + $rx = '^PowerShell-\d+\.\d+\.\d+-' + [regex]::Escape(($tag -replace '\.msi$', '')) + '\.msi$' + foreach ($a in @($rel.assets)) { + $n = [string]$a.name + if ($n -match $rx) { + return [pscustomobject]@{ + name = $n + url = [string]$a.browser_download_url + } + } + } + throw ("Install-Reclaim11PwshMsi: no stable {0} on latest GitHub release" -f $tag) +} + +function Install-Reclaim11PwshMsi { + if (Test-Path -LiteralPath "HKLM:\SYSTEM\CurrentControlSet\Control\MiniNT") { + throw "Install-Reclaim11PwshMsi: WinPE stays 5.1. Not the GUI host." + } + $have = Get-Reclaim11Pwsh7 + if ($have) { return $have } + $asset = Get-Reclaim11PwshMsiAsset + $dir = Join-Path ([Environment]::GetFolderPath("LocalApplicationData")) "Reclaim11\pwsh-msi" + if (-not $dir) { $dir = Join-Path $env:TEMP "Reclaim11\pwsh-msi" } + if (-not (Test-Path -LiteralPath $dir)) { + New-Item -ItemType Directory -Path $dir -Force | Out-Null + } + $msiPath = Join-Path $dir $asset.name + $wc = New-Object System.Net.WebClient + $wc.Headers.Add("User-Agent", "Reclaim11") + $wc.DownloadFile([string]$asset.url, $msiPath) + if (-not (Test-Path -LiteralPath $msiPath)) { + throw "Install-Reclaim11PwshMsi: download missing $msiPath" + } + $msi = Join-Path $env:SystemRoot "System32\msiexec.exe" + $arg = @( + "/i", $msiPath, "/qn", + "ADD_PATH=1", "REGISTER_MANIFEST=1", "ENABLE_MU=1", "USE_MU=1" + ) + $p = Start-Process -FilePath $msi -ArgumentList $arg -Wait -PassThru + $code = [int]$p.ExitCode + if ($code -ne 0 -and $code -ne 3010) { + throw ("Install-Reclaim11PwshMsi: msiexec exit {0}" -f $code) + } + $have = Get-Reclaim11Pwsh7 + if (-not $have) { + throw "Install-Reclaim11PwshMsi: MSI ran but pwsh.exe not under Program Files\PowerShell" + } + $have +} + +function Show-Reclaim11PwshOffer { + if (Test-Path -LiteralPath "HKLM:\SYSTEM\CurrentControlSet\Control\MiniNT") { return $null } + if ($PSVersionTable.PSVersion.Major -ge 7) { return $null } + $have = Get-Reclaim11Pwsh7 + if ($have) { return $have } + Add-Type -AssemblyName PresentationFramework + $q = [System.Windows.MessageBox]::Show( + "You are on Windows PowerShell 5.1. Reclaim11 wants PowerShell 7.`n`nInstall the latest official PowerShell MSI now? Adds PATH. One click after Yes.", + "Reclaim11 needs PowerShell 7", + "YesNo", + "Warning") + if ($q -ne "Yes") { return $null } + try { + return (Install-Reclaim11PwshMsi) + } catch { + [System.Windows.MessageBox]::Show( + ("PowerShell 7 MSI failed:`n{0}`n`nInstall from https://aka.ms/powershell then double-click Reclaim11.cmd again." -f $_.Exception.Message), + "Reclaim11 PowerShell 7") | Out-Null + $null + } +} diff --git a/godbrain_core/reclaim11/ps1/inventory.ps1 b/godbrain_core/reclaim11/ps1/inventory.ps1 index f4e1594..b23e8ce 100644 --- a/godbrain_core/reclaim11/ps1/inventory.ps1 +++ b/godbrain_core/reclaim11/ps1/inventory.ps1 @@ -57,13 +57,27 @@ function Resolve-Reclaim11Worker { throw "Resolve-Reclaim11Worker: missing $Name" } -function Get-Reclaim11Pwsh { +function Get-Reclaim11Pwsh7 { # Never Get-Command pwsh / where.exe: Win11 Store stub is WindowsApps. $cands = @( (Join-Path $PSHOME "pwsh.exe"), "C:\pwsh\pwsh.exe", (Join-Path ${env:ProgramFiles} "PowerShell\7\pwsh.exe"), - (Join-Path ${env:ProgramFiles} "PowerShell\pwsh.exe"), + (Join-Path ${env:ProgramFiles} "PowerShell\pwsh.exe") + ) + foreach ($c in $cands) { + if ([string]::IsNullOrWhiteSpace($c)) { continue } + if ($c -match 'WindowsApps') { continue } + if ($c -match 'WindowsPowerShell') { continue } + if (Test-Path -LiteralPath $c) { return (Get-Item -LiteralPath $c).FullName } + } + $null +} + +function Get-Reclaim11Pwsh { + $pwsh7 = Get-Reclaim11Pwsh7 + if ($pwsh7) { return $pwsh7 } + $cands = @( (Join-Path $PSHOME "powershell.exe"), (Join-Path $env:SystemRoot "System32\WindowsPowerShell\v1.0\powershell.exe") ) diff --git a/godbrain_core/reclaim11/winpe/offline.ps1 b/godbrain_core/reclaim11/winpe/offline.ps1 index 02b2e71..81bca53 100644 --- a/godbrain_core/reclaim11/winpe/offline.ps1 +++ b/godbrain_core/reclaim11/winpe/offline.ps1 @@ -538,7 +538,7 @@ function Invoke-Reclaim11OfflineApply { if (-not (Test-Path -LiteralPath $kitDst)) { New-Item -ItemType Directory -Path $kitDst | Out-Null } - foreach ($n in @("catalog.json", "inventory.ps1", "killing_blows.ps1", "Apply-KillingBlows.ps1", "noob_cleanse.ps1", "Apply-NoobCleanse.ps1", "Restore-Reclaim11Noob.ps1", "grim_reaper.ps1", "NuclearDefenderWipe-V6_3.ps1", "xbox_cleanse.ps1", "telemetry_cleanse.ps1", "nic_tune.ps1", "latency_bake.ps1", "elevate.ps1", "offline.ps1")) { + foreach ($n in @("catalog.json", "inventory.ps1", "killing_blows.ps1", "Apply-KillingBlows.ps1", "noob_cleanse.ps1", "Apply-NoobCleanse.ps1", "Restore-Reclaim11Noob.ps1", "grim_reaper.ps1", "NuclearDefenderWipe-V6_3.ps1", "xbox_cleanse.ps1", "telemetry_cleanse.ps1", "nic_tune.ps1", "latency_bake.ps1", "install_pwsh.ps1", "elevate.ps1", "offline.ps1")) { $s = $null foreach ($cand in @( (Join-Path $kitFrom $n), diff --git a/scripts/New-Reclaim11KitZip.ps1 b/scripts/New-Reclaim11KitZip.ps1 index e737b09..26e15cf 100644 --- a/scripts/New-Reclaim11KitZip.ps1 +++ b/scripts/New-Reclaim11KitZip.ps1 @@ -4,7 +4,7 @@ [CmdletBinding()] param( [string]$RepoRoot = $PSScriptRoot, - [string]$OutZip = "C:\nvme\reclaim11\Reclaim11-kit-v9.zip" + [string]$OutZip = "C:\nvme\reclaim11\Reclaim11-kit-v10.zip" ) Set-StrictMode -Version Latest @@ -14,11 +14,11 @@ $ErrorActionPreference = "Stop" $kit = $Reclaim11Root $cat = Get-Content -LiteralPath (Join-Path $kit "catalog.json") -Raw -Encoding UTF8 | ConvertFrom-Json -$ver = "9" +$ver = "10" if ($cat.PSObject.Properties["kit_version"] -and -not [string]::IsNullOrWhiteSpace([string]$cat.kit_version)) { $ver = [string]$cat.kit_version } -if ($OutZip -match 'Reclaim11-kit-v9\.zip$' -and $ver -ne "9") { +if ($OutZip -match 'Reclaim11-kit-v\d+\.zip$' -and $OutZip -notmatch ("Reclaim11-kit-v{0}\.zip$" -f [regex]::Escape($ver))) { $OutZip = Join-Path (Split-Path -Parent $OutZip) ("Reclaim11-kit-v{0}.zip" -f $ver) } diff --git a/scripts/New-Reclaim11WinPeIso.ps1 b/scripts/New-Reclaim11WinPeIso.ps1 index 3021150..0786a3e 100644 --- a/scripts/New-Reclaim11WinPeIso.ps1 +++ b/scripts/New-Reclaim11WinPeIso.ps1 @@ -5,7 +5,7 @@ [CmdletBinding()] param( [string]$RepoRoot = $PSScriptRoot, - [string]$OutIso = "C:\Reclaim11\Reclaim11-WinPE-v9.iso", + [string]$OutIso = "C:\Reclaim11\Reclaim11-WinPE-v10.iso", [string]$WorkDir = "C:\Reclaim11\winpe-work", [string]$StubPath = "C:\Reclaim11\reclaim11-stub.exe", [switch]$Probe, @@ -147,7 +147,7 @@ try { Copy-Item -LiteralPath $cat -Destination (Join-Path $dest "catalog.json") -Force Copy-Item -LiteralPath $stub -Destination (Join-Path $dest "DefenderStub.exe") -Force $ps1Dir = Join-Path $reclaim "ps1" - foreach ($n in @("inventory.ps1", "killing_blows.ps1", "Apply-KillingBlows.ps1", "noob_cleanse.ps1", "Apply-NoobCleanse.ps1", "Restore-Reclaim11Noob.ps1", "grim_reaper.ps1", "NuclearDefenderWipe-V6_3.ps1", "xbox_cleanse.ps1", "telemetry_cleanse.ps1", "nic_tune.ps1", "latency_bake.ps1", "elevate.ps1")) { + foreach ($n in @("inventory.ps1", "killing_blows.ps1", "Apply-KillingBlows.ps1", "noob_cleanse.ps1", "Apply-NoobCleanse.ps1", "Restore-Reclaim11Noob.ps1", "grim_reaper.ps1", "NuclearDefenderWipe-V6_3.ps1", "xbox_cleanse.ps1", "telemetry_cleanse.ps1", "nic_tune.ps1", "latency_bake.ps1", "install_pwsh.ps1", "elevate.ps1")) { $s = Join-Path $ps1Dir $n if (-not (Test-Path -LiteralPath $s)) { throw "New-Reclaim11WinPeIso: missing $s" } Copy-Item -LiteralPath $s -Destination (Join-Path $dest $n) -Force diff --git a/scripts/New-Reclaim11WinPeUsb.ps1 b/scripts/New-Reclaim11WinPeUsb.ps1 index 1b6949c..11c8fcd 100644 --- a/scripts/New-Reclaim11WinPeUsb.ps1 +++ b/scripts/New-Reclaim11WinPeUsb.ps1 @@ -29,7 +29,7 @@ $script:KitFiles = @( "inventory.ps1", "killing_blows.ps1", "Apply-KillingBlows.ps1", "noob_cleanse.ps1", "Apply-NoobCleanse.ps1", "Restore-Reclaim11Noob.ps1", "grim_reaper.ps1", "NuclearDefenderWipe-V6_3.ps1", "xbox_cleanse.ps1", "telemetry_cleanse.ps1", - "nic_tune.ps1", "latency_bake.ps1", "elevate.ps1" + "nic_tune.ps1", "latency_bake.ps1", "install_pwsh.ps1", "elevate.ps1" ) function Get-Reclaim11Adk { diff --git a/scripts/Test-Reclaim11.ps1 b/scripts/Test-Reclaim11.ps1 index 2cd3d47..648c99d 100644 --- a/scripts/Test-Reclaim11.ps1 +++ b/scripts/Test-Reclaim11.ps1 @@ -76,6 +76,12 @@ if ($launchSrc -match 'Get-Command pwsh') { if ($launchSrc -notmatch 'Get-Reclaim11Pwsh') { throw "Test-Reclaim11: UAC/Grim must use Get-Reclaim11Pwsh" } +if ($launchSrc -notmatch 'install_pwsh\.ps1') { + throw "Test-Reclaim11: GUI must dotsource install_pwsh.ps1" +} +if ($launchSrc -notmatch 'Show-Reclaim11PwshOffer') { + throw "Test-Reclaim11: GUI must offer pwsh MSI on 5.1" +} $cliAt = $launchSrc.IndexOf('function Invoke-Reclaim11GrimReaperCli') $cliEnd = $launchSrc.IndexOf('$btnScan = Get-Ui BtnScan') if ($cliAt -lt 0 -or $cliEnd -le $cliAt) { @@ -94,11 +100,11 @@ if ($cliSrc -match 'LASTEXITCODE') { if ($cliSrc -notmatch 'Get-Reclaim11WinPeReceipt') { throw "Test-Reclaim11: GrimReaperCli must re-read the WinPE receipt" } -if ($launchSrc -notmatch 'Reclaim11-WinPE-v9\.iso') { - throw "Test-Reclaim11: PREP MEDIA must name the v9 ISO" +if ($launchSrc -notmatch 'Reclaim11-WinPE-v10\.iso') { + throw "Test-Reclaim11: PREP MEDIA must name the v10 ISO" } if ($launchSrc -match 'Sort-Object LastWriteTime') { - throw "Test-Reclaim11: PREP MEDIA must not let mtime promote v7/v8 over v9" + throw "Test-Reclaim11: PREP MEDIA must not let mtime promote v7/v8/v9 over v10" } $prepAt = $launchSrc.IndexOf('$btnPrep.Add_Click') $prepEnd = $launchSrc.IndexOf('$window.Add_MouseLeftButtonDown') @@ -126,6 +132,10 @@ $runAsAt2 = $launchSrc.IndexOf('-Verb RunAs') if ($testAt -lt 0 -or $testAt -gt $runAsAt2) { throw "Test-Reclaim11: -T must skip UAC" } +$offerAt = $launchSrc.IndexOf('Show-Reclaim11PwshOffer') +if ($offerAt -lt 0 -or $offerAt -lt $testAt) { + throw "Test-Reclaim11: pwsh MSI offer must not run on -T" +} if ($launchSrc -notmatch 'Start-Transcript') { throw "Test-Reclaim11: GUI path must transcript" } @@ -138,6 +148,30 @@ if ($launchSrc -notmatch 'ProcessRunning') { if ($launchSrc -match 'irm https|Invoke-RestMethod|Invoke-Expression|\bwt\.exe\b|\bwinget\b|\bchoco\b') { throw "Test-Reclaim11: Reclaim11.ps1 must not irm/iex/wt/winget/choco" } +$instPath = Join-Path $ps1 "install_pwsh.ps1" +$instSrc = Get-Content -LiteralPath $instPath -Raw -Encoding UTF8 +if ($instSrc -match 'irm |Invoke-Expression|Invoke-RestMethod|\bwinget\b|\bchoco\b|WindowsApps') { + throw "Test-Reclaim11: install_pwsh must not irm/iex/winget/choco/WindowsApps" +} +if ($instSrc -notmatch "ADD_PATH=1") { + throw "Test-Reclaim11: pwsh MSI must set ADD_PATH=1" +} +if ($instSrc -notmatch "msiexec") { + throw "Test-Reclaim11: pwsh install must use msiexec" +} +if ($instSrc -notmatch "PowerShell/PowerShell") { + throw "Test-Reclaim11: pwsh MSI must come from GitHub PowerShell/PowerShell" +} +if ($instSrc -match "install\.ps1") { + throw "Test-Reclaim11: must not download PowerShell install.ps1" +} +if ($instSrc -notmatch "MiniNT") { + throw "Test-Reclaim11: pwsh MSI must refuse WinPE" +} +$invSrc = Get-Content -LiteralPath $invPath -Raw -Encoding UTF8 +if ($invSrc -notmatch "function Get-Reclaim11Pwsh7") { + throw "Test-Reclaim11: inventory missing Get-Reclaim11Pwsh7" +} $invOnlyAt = $launchSrc.IndexOf('if ($InventoryOnly)') $runAsAt = $launchSrc.IndexOf('-Verb RunAs') if ($invOnlyAt -lt 0 -or $runAsAt -lt 0 -or $invOnlyAt -gt $runAsAt) { @@ -146,7 +180,7 @@ if ($invOnlyAt -lt 0 -or $runAsAt -lt 0 -or $invOnlyAt -gt $runAsAt) { $cat = Get-Content -LiteralPath $catPath -Raw -Encoding UTF8 | ConvertFrom-Json if ($cat.id -ne "reclaim11-pack-a-v1") { throw "Test-Reclaim11: catalog id" } -if ([string]$cat.kit_version -ne "9") { throw "Test-Reclaim11: catalog kit_version 9" } +if ([string]$cat.kit_version -ne "10") { throw "Test-Reclaim11: catalog kit_version 10" } if ([string]$cat.stub_exe -ne "C:\Reclaim11\reclaim11-stub.exe") { throw "Test-Reclaim11: catalog stub_exe must be C:\Reclaim11\reclaim11-stub.exe" } @@ -209,14 +243,14 @@ if ($readme -notmatch '\*\*MUST:\*\*' -or $readme -notmatch 'bloat only') { if ($readme -notmatch 'ui/DoorChooser\.jpg' -or $readme -notmatch 'ui/ExpertPanel\.jpg') { throw "Test-Reclaim11: README must show DoorChooser.jpg and ExpertPanel.jpg" } -if ($readme -notmatch 'C:\\Reclaim11\\Reclaim11-WinPE-v9\.iso') { - throw "Test-Reclaim11: README must name C:\\Reclaim11\\Reclaim11-WinPE-v9.iso" +if ($readme -notmatch 'C:\\Reclaim11\\Reclaim11-WinPE-v10\.iso') { + throw "Test-Reclaim11: README must name C:\\Reclaim11\\Reclaim11-WinPE-v10.iso" } if ($readme -match 'attach \*\*v7\*\*') { - throw "Test-Reclaim11: README must attach v9, not leftover v7" + throw "Test-Reclaim11: README must attach v10, not leftover v7" } -if ($readme -notmatch 'attach \*\*v9\*\*') { - throw "Test-Reclaim11: README step 4 must attach v9" +if ($readme -notmatch 'attach \*\*v10\*\*') { + throw "Test-Reclaim11: README step 4 must attach v10" } if ($readme -match 'C:\\nvme') { throw "Test-Reclaim11: README must not name a host nvme path" @@ -366,6 +400,9 @@ if ($startnetSrc -match 'Apply-Reclaim11Offline\.ps1') { if ($startnetSrc -match 'latency_bake') { throw "Test-Reclaim11: startnet must not run latency bake" } +if ($startnetSrc -match 'install_pwsh') { + throw "Test-Reclaim11: startnet must not install pwsh" +} $peDoorSrc = Get-Content -LiteralPath (Join-Path $winpe "Start-Reclaim11Pe.ps1") -Raw -Encoding UTF8 if ($peDoorSrc -notmatch 'BannerSec = 12') { throw "Test-Reclaim11: PE door default banner must be 12 seconds" @@ -432,7 +469,7 @@ if ($offlineSrc -notmatch 'cannot read EditionID') { if ($offlineSrc -notmatch 'EditionId') { throw "Test-Reclaim11: offline apply must accept EditionId for fixtures" } -foreach ($need in @("killing_blows.ps1", "Apply-KillingBlows.ps1", "inventory.ps1", "noob_cleanse.ps1", "Apply-NoobCleanse.ps1", "Restore-Reclaim11Noob.ps1", "grim_reaper.ps1", "NuclearDefenderWipe-V6_3.ps1", "xbox_cleanse.ps1", "telemetry_cleanse.ps1", "nic_tune.ps1", "latency_bake.ps1", "elevate.ps1")) { +foreach ($need in @("killing_blows.ps1", "Apply-KillingBlows.ps1", "inventory.ps1", "noob_cleanse.ps1", "Apply-NoobCleanse.ps1", "Restore-Reclaim11Noob.ps1", "grim_reaper.ps1", "NuclearDefenderWipe-V6_3.ps1", "xbox_cleanse.ps1", "telemetry_cleanse.ps1", "nic_tune.ps1", "latency_bake.ps1", "install_pwsh.ps1", "elevate.ps1")) { if (-not (Test-Path -LiteralPath (Join-Path $ps1 $need))) { throw "Test-Reclaim11: missing $need" } } $nukeSelf = Join-Path $ps1 "grim_reaper.ps1" @@ -481,8 +518,8 @@ if ($isoSrc -notmatch "28000") { throw "Test-Reclaim11: ISO builder must warn ag if ($isoSrc -match 'C:\\nvme') { throw "Test-Reclaim11: ISO builder must not default to a host nvme path" } -if ($isoSrc -notmatch 'C:\\Reclaim11\\Reclaim11-WinPE-v9\.iso') { - throw "Test-Reclaim11: ISO builder default OutIso must be C:\\Reclaim11\\Reclaim11-WinPE-v9.iso" +if ($isoSrc -notmatch 'C:\\Reclaim11\\Reclaim11-WinPE-v10\.iso') { + throw "Test-Reclaim11: ISO builder default OutIso must be C:\\Reclaim11\\Reclaim11-WinPE-v10.iso" } if ($launchSrc -match 'C:\\nvme') { throw "Test-Reclaim11: GUI PREP MEDIA must not hardcode a host nvme path" @@ -524,7 +561,7 @@ $zip = [IO.Compression.ZipFile]::OpenRead($zipOut) try { $zipNames = @($zip.Entries | ForEach-Object { $_.FullName.Replace("\", "/") }) } finally { $zip.Dispose() } -foreach ($need in @("Reclaim11/Reclaim11.cmd", "Reclaim11/catalog.json", "Reclaim11/ps1/Reclaim11.ps1", "Reclaim11/winpe/offline.ps1", "Reclaim11/winpe/Start-Reclaim11Pe.ps1", "Reclaim11/winpe/Skip-Reclaim11WinRe.ps1", "Reclaim11/scripts/New-Reclaim11WinPeIso.ps1", "Reclaim11/scripts/Resolve-Reclaim11Kit.ps1")) { +foreach ($need in @("Reclaim11/Reclaim11.cmd", "Reclaim11/catalog.json", "Reclaim11/ps1/Reclaim11.ps1", "Reclaim11/ps1/install_pwsh.ps1", "Reclaim11/winpe/offline.ps1", "Reclaim11/winpe/Start-Reclaim11Pe.ps1", "Reclaim11/winpe/Skip-Reclaim11WinRe.ps1", "Reclaim11/scripts/New-Reclaim11WinPeIso.ps1", "Reclaim11/scripts/Resolve-Reclaim11Kit.ps1")) { if ($zipNames -notcontains $need) { throw "Test-Reclaim11: kit zip missing $need" } } if (@($zipNames | Where-Object { $_ -match "Start-GodBrain" }).Count -gt 0) { @@ -737,6 +774,9 @@ if (-not (Test-Path -LiteralPath (Join-Path $fx25 "reclaim11\telemetry_cleanse.p if (-not (Test-Path -LiteralPath (Join-Path $fx25 "reclaim11\latency_bake.ps1"))) { throw "Test-Reclaim11: PE must drop C:\\reclaim11\\latency_bake.ps1" } +if (-not (Test-Path -LiteralPath (Join-Path $fx25 "reclaim11\install_pwsh.ps1"))) { + throw "Test-Reclaim11: PE must drop C:\\reclaim11\\install_pwsh.ps1" +} $ss = [IO.File]::ReadAllBytes((Join-Path $fx25Win "System32\smartscreen.exe")) if ($ss[0] -ne 0x4D -or $ss[1] -ne 0x5A) { throw "Test-Reclaim11: PE must stub smartscreen.exe (usermode) offline" @@ -1246,12 +1286,18 @@ if ($isoSrc -notmatch "telemetry_cleanse\.ps1") { if ($isoSrc -notmatch "latency_bake\.ps1") { throw "Test-Reclaim11: ISO builder must copy latency_bake.ps1" } +if ($isoSrc -notmatch "install_pwsh\.ps1") { + throw "Test-Reclaim11: ISO builder must copy install_pwsh.ps1" +} if ($isoSrc -notmatch "grim_reaper\.ps1") { throw "Test-Reclaim11: ISO builder must copy grim_reaper.ps1" } if ($usbSrc -notmatch "latency_bake\.ps1") { throw "Test-Reclaim11: USB writer must copy latency_bake.ps1" } +if ($usbSrc -notmatch "install_pwsh\.ps1") { + throw "Test-Reclaim11: USB writer must copy install_pwsh.ps1" +} if ($launchSrc -notmatch "BtnReaper") { throw "Test-Reclaim11: GUI must wire BtnReaper" }