diff --git a/godbrain_core/reclaim11/README.md b/godbrain_core/reclaim11/README.md index 04d4528..d2cd974 100644 --- a/godbrain_core/reclaim11/README.md +++ b/godbrain_core/reclaim11/README.md @@ -14,9 +14,10 @@ until a WinPE receipt. Exact flags are under Advanced. 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`. If you only have - Windows PowerShell 5.1, the GUI offers the official PowerShell 7 MSI - (adds PATH). WinPE stays 5.1. +2. Double-click `Reclaim11.cmd`. You do not type `pwsh`. The `.cmd` hops + to a hidden host so Windows Terminal does not stay as an empty black + window. 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: diff --git a/godbrain_core/reclaim11/Reclaim11.cmd b/godbrain_core/reclaim11/Reclaim11.cmd index 4284288..d45c477 100644 --- a/godbrain_core/reclaim11/Reclaim11.cmd +++ b/godbrain_core/reclaim11/Reclaim11.cmd @@ -1,8 +1,15 @@ @echo off setlocal EnableExtensions REM Double-click door. Do not type pwsh. UAC is inside Reclaim11.ps1. +REM Win11 default terminal is Windows Terminal. start pwsh -WindowStyle Hidden +REM from this .cmd is an empty black WT window. Reclaim11.vbs Run 0 is not. set "KIT=%~dp0" +set "VBS=%KIT%Reclaim11.vbs" set "GUI=%KIT%ps1\Reclaim11.ps1" +if exist "%VBS%" ( + start "" "%SystemRoot%\System32\wscript.exe" //nologo "%VBS%" + exit /b 0 +) if not exist "%GUI%" ( echo Reclaim11.cmd: missing ps1\Reclaim11.ps1 exit /b 1 diff --git a/godbrain_core/reclaim11/Reclaim11.vbs b/godbrain_core/reclaim11/Reclaim11.vbs new file mode 100644 index 0000000..ad1a45a --- /dev/null +++ b/godbrain_core/reclaim11/Reclaim11.vbs @@ -0,0 +1,34 @@ +' Double-click door helper. No console. Not Heal. +' Win11 default terminal is Windows Terminal. start pwsh -WindowStyle Hidden +' from a .cmd opens an empty WT window. Wscript.Shell Run 0 does not. +Option Explicit +Dim fso, sh, kit, gui, pwsh, pf, windir, cmd +Set fso = CreateObject("Scripting.FileSystemObject") +Set sh = CreateObject("Wscript.Shell") +kit = fso.GetParentFolderName(Wscript.ScriptFullName) +gui = kit & "\ps1\Reclaim11.ps1" +If Not fso.FileExists(gui) Then + sh.Popup "Reclaim11: missing ps1\Reclaim11.ps1", 8, "Reclaim11", 16 + Wscript.Quit 1 +End If +pf = sh.ExpandEnvironmentStrings("%ProgramFiles%") +windir = sh.ExpandEnvironmentStrings("%SystemRoot%") +pwsh = "" +If fso.FileExists("C:\pwsh\pwsh.exe") Then pwsh = "C:\pwsh\pwsh.exe" +If pwsh = "" Then + If fso.FileExists(pf & "\PowerShell\7\pwsh.exe") Then pwsh = pf & "\PowerShell\7\pwsh.exe" +End If +If pwsh = "" Then + If fso.FileExists(pf & "\PowerShell\pwsh.exe") Then pwsh = pf & "\PowerShell\pwsh.exe" +End If +If pwsh = "" Then pwsh = windir & "\System32\WindowsPowerShell\v1.0\powershell.exe" +If InStr(1, pwsh, "WindowsApps", vbTextCompare) > 0 Then + sh.Popup "Reclaim11: refusing WindowsApps PowerShell stub", 8, "Reclaim11", 16 + Wscript.Quit 1 +End If +If Not fso.FileExists(pwsh) Then + sh.Popup "Reclaim11: no PowerShell found", 8, "Reclaim11", 16 + Wscript.Quit 1 +End If +cmd = """" & pwsh & """ -STA -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File """ & gui & """" +sh.Run cmd, 0, False diff --git a/godbrain_core/reclaim11/ps1/Reclaim11.ps1 b/godbrain_core/reclaim11/ps1/Reclaim11.ps1 index 45e33ba..935f0ad 100644 --- a/godbrain_core/reclaim11/ps1/Reclaim11.ps1 +++ b/godbrain_core/reclaim11/ps1/Reclaim11.ps1 @@ -84,6 +84,30 @@ if ($Test) { return } +function Start-Reclaim11HiddenHost { + param( + [Parameter(Mandatory)][string]$FilePath, + [Parameter(Mandatory)][string[]]$ArgumentList, + [switch]$RunAs + ) + $quoted = New-Object System.Collections.Generic.List[string] + foreach ($a in $ArgumentList) { + $s = [string]$a + if ($s -match '[\s"]') { + [void]$quoted.Add('"' + ($s -replace '"', '""') + '"') + } else { + [void]$quoted.Add($s) + } + } + $argLine = ($quoted -join " ") + $verb = "" + if ($RunAs) { $verb = "runas" } + $app = New-Object -ComObject Shell.Application + # 0 = SW_HIDE. Start-Process -WindowStyle Hidden opens Windows Terminal + # as an empty black window when WT is the default console host. + [void]$app.ShellExecute($FilePath, $argLine, "", $verb, 0) +} + $sta = [Threading.Thread]::CurrentThread.GetApartmentState() $admin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator) @@ -93,11 +117,7 @@ if ($sta -ne "STA" -or -not $admin) { "-STA", "-NoProfile", "-WindowStyle", "Hidden", "-ExecutionPolicy", "Bypass", "-File", $MyInvocation.MyCommand.Path ) if ($WinPeLog) { $arg += @("-WinPeLog", $WinPeLog) } - if (-not $admin) { - Start-Process -FilePath $pwsh -ArgumentList $arg -Verb RunAs -WindowStyle Hidden - } else { - Start-Process -FilePath $pwsh -ArgumentList $arg -WindowStyle Hidden - } + Start-Reclaim11HiddenHost -FilePath $pwsh -ArgumentList $arg -RunAs:(-not $admin) return } @@ -108,7 +128,7 @@ if ($PSVersionTable.PSVersion.Major -lt 7) { "-STA", "-NoProfile", "-WindowStyle", "Hidden", "-ExecutionPolicy", "Bypass", "-File", $MyInvocation.MyCommand.Path ) if ($WinPeLog) { $arg += @("-WinPeLog", $WinPeLog) } - Start-Process -FilePath $pwsh7 -ArgumentList $arg -WindowStyle Hidden + Start-Reclaim11HiddenHost -FilePath $pwsh7 -ArgumentList $arg return } } diff --git a/scripts/New-Reclaim11KitZip.ps1 b/scripts/New-Reclaim11KitZip.ps1 index 36cacd8..cd35bc4 100644 --- a/scripts/New-Reclaim11KitZip.ps1 +++ b/scripts/New-Reclaim11KitZip.ps1 @@ -24,6 +24,7 @@ if ($OutZip -match 'Reclaim11-kit-v\d+\.zip$' -and $OutZip -notmatch ("Reclaim11 $need = @( (Join-Path $kit "Reclaim11.cmd"), + (Join-Path $kit "Reclaim11.vbs"), (Join-Path $kit "catalog.json"), (Join-Path $kit "README.md"), (Join-Path $kit "ps1\Reclaim11.ps1"), @@ -52,6 +53,7 @@ New-Item -ItemType Directory -Path (Join-Path $stage "scripts") | Out-Null New-Item -ItemType Directory -Path (Join-Path $stage "brave-policy") | Out-Null Copy-Item -LiteralPath (Join-Path $kit "Reclaim11.cmd") -Destination (Join-Path $stage "Reclaim11.cmd") -Force +Copy-Item -LiteralPath (Join-Path $kit "Reclaim11.vbs") -Destination (Join-Path $stage "Reclaim11.vbs") -Force Copy-Item -LiteralPath (Join-Path $kit "catalog.json") -Destination (Join-Path $stage "catalog.json") -Force Copy-Item -LiteralPath (Join-Path $kit "README.md") -Destination (Join-Path $stage "README.md") -Force Get-ChildItem -LiteralPath (Join-Path $kit "ps1") -Filter *.ps1 | ForEach-Object { diff --git a/scripts/New-Reclaim11WinPeUsb.ps1 b/scripts/New-Reclaim11WinPeUsb.ps1 index 011761c..b002e9a 100644 --- a/scripts/New-Reclaim11WinPeUsb.ps1 +++ b/scripts/New-Reclaim11WinPeUsb.ps1 @@ -207,6 +207,7 @@ $kitDest = Join-Path $usbRoot "reclaim11" if (-not (Test-Path -LiteralPath $kitDest)) { New-Item -ItemType Directory -Path $kitDest | Out-Null } Copy-Item -LiteralPath (Join-Path $reclaim "catalog.json") -Destination (Join-Path $kitDest "catalog.json") -Force Copy-Item -LiteralPath (Join-Path $reclaim "Reclaim11.cmd") -Destination (Join-Path $kitDest "Reclaim11.cmd") -Force +Copy-Item -LiteralPath (Join-Path $reclaim "Reclaim11.vbs") -Destination (Join-Path $kitDest "Reclaim11.vbs") -Force $ps1Dest = Join-Path $kitDest "ps1" if (-not (Test-Path -LiteralPath $ps1Dest)) { New-Item -ItemType Directory -Path $ps1Dest | Out-Null } foreach ($n in $script:KitFiles) { diff --git a/scripts/Test-Reclaim11.ps1 b/scripts/Test-Reclaim11.ps1 index 845804d..bc3a5ad 100644 --- a/scripts/Test-Reclaim11.ps1 +++ b/scripts/Test-Reclaim11.ps1 @@ -50,9 +50,33 @@ Get-ChildItem -LiteralPath $root -Recurse -File | ForEach-Object { } } $cmdSrc = Get-Content -LiteralPath $cmdPath -Raw -Encoding ASCII +$vbsPath = Join-Path $root "Reclaim11.vbs" +if (-not (Test-Path -LiteralPath $vbsPath)) { throw "Test-Reclaim11: missing Reclaim11.vbs" } +$vbsSrc = Get-Content -LiteralPath $vbsPath -Raw -Encoding ASCII if ($cmdSrc -notmatch 'ps1\\Reclaim11\.ps1') { throw "Test-Reclaim11: Reclaim11.cmd must launch ps1\Reclaim11.ps1" } +if ($cmdSrc -notmatch 'wscript\.exe') { + throw "Test-Reclaim11: Reclaim11.cmd must hop to wscript (WT swallows .cmd)" +} +if ($cmdSrc -notmatch 'Reclaim11\.vbs') { + throw "Test-Reclaim11: Reclaim11.cmd must launch Reclaim11.vbs" +} +if ($cmdSrc -match 'wt\.exe') { + throw "Test-Reclaim11: Reclaim11.cmd must not call wt.exe" +} +if ($vbsSrc -notmatch 'ps1\\Reclaim11\.ps1') { + throw "Test-Reclaim11: Reclaim11.vbs must launch ps1\Reclaim11.ps1" +} +if ($vbsSrc -notmatch 'sh\.Run cmd, 0, False') { + throw "Test-Reclaim11: Reclaim11.vbs must Run 0 (hidden, no WT window)" +} +if ($vbsSrc -match 'WindowsApps' -and $vbsSrc -notmatch 'refusing WindowsApps') { + throw "Test-Reclaim11: Reclaim11.vbs must not use the WindowsApps stub" +} +if ($vbsSrc -match 'where pwsh') { + throw "Test-Reclaim11: Reclaim11.vbs must not where pwsh (WindowsApps stub)" +} if ($cmdSrc -notmatch 'WindowStyle Hidden') { throw "Test-Reclaim11: Reclaim11.cmd must hide the PowerShell console" } @@ -107,7 +131,13 @@ $launchSrc = Get-Content -LiteralPath $launch -Raw -Encoding UTF8 if ($launchSrc -notmatch 'LanguageMode -ne "FullLanguage"') { throw "Test-Reclaim11: Reclaim11.ps1 must refuse ConstrainedLanguage" } -if ($launchSrc -notmatch '-Verb RunAs') { +if ($launchSrc -notmatch 'function Start-Reclaim11HiddenHost') { + throw "Test-Reclaim11: STA/admin relaunch must ShellExecute SW_HIDE (WT ignores WindowStyle Hidden)" +} +if ($launchSrc -notmatch 'ShellExecute') { + throw "Test-Reclaim11: GUI path must UAC-relaunch via ShellExecute" +} +if ($launchSrc -notmatch '"runas"') { throw "Test-Reclaim11: GUI path must UAC-relaunch" } if ($launchSrc -notmatch '-WindowStyle Hidden') { @@ -693,6 +723,9 @@ if ($usbSrc -notmatch "Get-Reclaim11IsoStub") { if ($usbSrc -notmatch "ListJson") { throw "Test-Reclaim11: USB writer must list sticks as JSON for PREP MEDIA" } +if ($usbSrc -notmatch "Reclaim11\.vbs") { + throw "Test-Reclaim11: USB kit copy must include Reclaim11.vbs" +} $zipBuild = Join-Path $RepoRoot "scripts\New-Reclaim11KitZip.ps1" if (-not (Test-Path -LiteralPath $zipBuild)) { throw "Test-Reclaim11: missing New-Reclaim11KitZip.ps1" } @@ -707,7 +740,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/ps1/install_pwsh.ps1", "Reclaim11/winpe/offline.ps1", "Reclaim11/winpe/Start-Reclaim11Pe.ps1", "Reclaim11/winpe/Skip-Reclaim11WinRe.ps1", "Reclaim11/winpe/reclaim11-stub.exe", "Reclaim11/scripts/New-Reclaim11WinPeIso.ps1", "Reclaim11/scripts/Resolve-Reclaim11Kit.ps1")) { +foreach ($need in @("Reclaim11/Reclaim11.cmd", "Reclaim11/Reclaim11.vbs", "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/winpe/reclaim11-stub.exe", "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) {