# Mr. Mags one-click installer engine. # # Downloads the desktop installer and the browser extension from cdn.mrmags.org, # installs the desktop app silently to the per-user location (no admin needed), # extracts the extension to a known stable path, and opens the keyholder's # browser to chrome://extensions/ with the path copied to their clipboard so # they only have to click Developer mode + Load unpacked + paste + Open. # # Invoked by Mr-Mags-Quick-Install.cmd via PowerShell -EncodedCommand. $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' # ── Constants ───────────────────────────────────────────────────────────── $CdnBase = 'https://cdn.mrmags.org' $DesktopFile = 'Mr-Mags-Setup.exe' $ExtensionFile = 'mrmags-extension.zip' $ExtensionDir = Join-Path $env:LOCALAPPDATA 'MrMagsExtension' $TempDir = Join-Path $env:TEMP ("mrmags-install-{0}" -f (Get-Random -Maximum 99999)) # ── Helpers ─────────────────────────────────────────────────────────────── function Write-Banner { $bar = ('=' * 60) Write-Host '' Write-Host $bar -ForegroundColor DarkCyan Write-Host ' Mr. Mags :: one-click install' -ForegroundColor White Write-Host ' Desktop app + browser extension. About 60 seconds.' -ForegroundColor Gray Write-Host $bar -ForegroundColor DarkCyan Write-Host '' } function Write-Step([string]$msg) { Write-Host " -> $msg" -ForegroundColor Cyan } function Write-Done([string]$msg) { Write-Host " $msg" -ForegroundColor Green } function Write-Soft([string]$msg) { Write-Host " $msg" -ForegroundColor DarkGray } function Fetch-File([string]$url, [string]$dest, [string]$label) { Write-Step "Downloading $label" try { # IWR with -UseBasicParsing avoids IE engine dependency on older Win. Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing } catch { throw "Download failed for $label : $($_.Exception.Message)" } if (-not (Test-Path $dest)) { throw "Download finished but file missing: $dest" } $size = [math]::Round((Get-Item $dest).Length / 1MB, 1) Write-Done "$label downloaded ($size MB)" } function Find-Browser { # Prefer Chrome; fall back to Edge. Both honor chrome://extensions style # URLs for their own extension UIs (edge://extensions for Edge). $candidates = @( @{ name='Chrome'; ext='chrome://extensions/'; paths=@( (Join-Path $env:LOCALAPPDATA 'Google\Chrome\Application\chrome.exe'), 'C:\Program Files\Google\Chrome\Application\chrome.exe', 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe' ) }, @{ name='Edge'; ext='edge://extensions/'; paths=@( 'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe', 'C:\Program Files\Microsoft\Edge\Application\msedge.exe' ) } ) foreach ($c in $candidates) { foreach ($p in $c.paths) { if (Test-Path $p) { return [pscustomobject]@{ Name=$c.name; Path=$p; Url=$c.ext } } } } return $null } # ── Main flow ───────────────────────────────────────────────────────────── try { Write-Banner New-Item -ItemType Directory -Path $TempDir -Force | Out-Null Write-Soft "Working folder: $TempDir" # Step 1: download installer + extension in parallel-ish (sequential is fine) $desktopPath = Join-Path $TempDir $DesktopFile Fetch-File "$CdnBase/$DesktopFile" $desktopPath 'desktop installer (~180 MB)' $extPath = Join-Path $TempDir $ExtensionFile Fetch-File "$CdnBase/$ExtensionFile" $extPath 'browser extension (~30 KB)' # Step 2: run the desktop installer silently. NSIS /S = silent install. # Per-user install (no admin), default location LOCALAPPDATA\Programs\mrmags-app. Write-Step 'Installing desktop app (silent, no admin required)' $p = Start-Process -FilePath $desktopPath -ArgumentList '/S' -PassThru -Wait if ($p.ExitCode -ne 0) { throw "Desktop installer exited with code $($p.ExitCode)" } Write-Done 'Desktop app installed' # Step 3: extract extension to a STABLE path the keyholder can paste into # Chrome. Purge old contents first so a re-install picks up the new # manifest.json instead of mixing versions. Write-Step 'Setting up browser extension files' if (Test-Path $ExtensionDir) { Remove-Item -Path $ExtensionDir -Recurse -Force } New-Item -ItemType Directory -Path $ExtensionDir -Force | Out-Null Expand-Archive -Path $extPath -DestinationPath $ExtensionDir -Force if (-not (Test-Path (Join-Path $ExtensionDir 'manifest.json'))) { # The zip may have a top-level folder; promote its contents. $inner = Get-ChildItem -Path $ExtensionDir -Directory | Select-Object -First 1 if ($inner) { Get-ChildItem -Path $inner.FullName -Force | Move-Item -Destination $ExtensionDir -Force Remove-Item -Path $inner.FullName -Recurse -Force } } if (-not (Test-Path (Join-Path $ExtensionDir 'manifest.json'))) { throw "Extension extracted but manifest.json not found at $ExtensionDir" } Write-Done "Extension files at: $ExtensionDir" # Step 4: copy the path to clipboard so the user only has to paste. try { Set-Clipboard -Value $ExtensionDir Write-Done 'Extension path copied to clipboard' } catch { Write-Soft "(Could not copy to clipboard automatically; the path will be shown for you to copy manually.)" } # Step 5: launch browser to extensions page. $browser = Find-Browser if ($browser) { Write-Step "Opening $($browser.Name) to the extensions page" Start-Process -FilePath $browser.Path -ArgumentList $browser.Url | Out-Null Write-Done "$($browser.Name) opened to $($browser.Url)" } else { Write-Soft "No supported browser found. Open Chrome or Edge and go to chrome://extensions yourself." } # Step 6: friendly finish screen with the manual step + path on screen. $bar = ('=' * 60) Write-Host '' Write-Host $bar -ForegroundColor Green Write-Host ' Almost done! One small step in your browser:' -ForegroundColor White Write-Host $bar -ForegroundColor Green Write-Host '' Write-Host ' 1. Toggle ' -NoNewline; Write-Host 'Developer mode' -ForegroundColor Yellow -NoNewline; Write-Host ' (top-right of the extensions page).' Write-Host ' 2. Click ' -NoNewline; Write-Host 'Load unpacked' -ForegroundColor Yellow -NoNewline; Write-Host '.' Write-Host ' 3. Paste this path into the folder picker:' -NoNewline; Write-Host '' Write-Host '' Write-Host " $ExtensionDir" -ForegroundColor Cyan Write-Host '' Write-Host ' (The path is already in your clipboard. Ctrl+V in the picker.)' -ForegroundColor DarkGray Write-Host '' Write-Host ' 4. Click ' -NoNewline; Write-Host 'Select Folder' -ForegroundColor Yellow -NoNewline; Write-Host '. Mr. Mags appears in your extension list.' Write-Host ' 5. Pin it to your toolbar (puzzle icon -> pin).' Write-Host '' Write-Host $bar -ForegroundColor Green Write-Host ' Desktop app is already installed. It will open from your Start menu' -ForegroundColor Gray Write-Host ' or system tray. Memory lives at: %APPDATA%\Mr. Mags' -ForegroundColor Gray Write-Host ' Questions: hello@mrmags.org' -ForegroundColor Gray Write-Host $bar -ForegroundColor Green Write-Host '' Write-Host 'Press any key to close this window...' -ForegroundColor DarkGray $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') exit 0 } catch { Write-Host '' Write-Host ' Install failed:' -ForegroundColor Red Write-Host " $($_.Exception.Message)" -ForegroundColor Red Write-Host '' Write-Host ' Try the manual install at https://mrmags.org/install' -ForegroundColor Yellow Write-Host ' or email hello@mrmags.org for help.' -ForegroundColor Yellow Write-Host '' Write-Host 'Press any key to close this window...' -ForegroundColor DarkGray $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') exit 1 } finally { if (Test-Path $TempDir) { try { Remove-Item -Path $TempDir -Recurse -Force -ErrorAction SilentlyContinue } catch {} } }