#requires -Version 5.1 <# MajicNode.ps1 - MAJIC Media Node LITE bootstrap (download once, never again). This tiny bootstrap always pulls the LATEST node payload from MAJIC and installs or UPDATES this machine's media node. You never need to re-download a new build - this same file fetches whatever the current version is. - First run : installs the node (asks for your MAJIC account once). - Later runs : UPDATES the existing node in place (no duplicate nodes/tasks). - It also registers a daily auto-update check so nodes self-update silently. Run from an ELEVATED PowerShell (Run as Administrator): powershell -NoProfile -ExecutionPolicy Bypass -File .\MajicNode.ps1 Options: -Update Force an update check now (used by the scheduled auto-updater). -Channel Manifest base URL (default https://node.appmajic.ai). #> [CmdletBinding()] param( [switch]$Update, [string]$Channel = 'https://node.appmajic.ai', [string]$Email = '', [securestring]$Password ) $ErrorActionPreference = 'Stop' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $Root = 'C:\Majic\media' $CacheDir = Join-Path $Root 'payload' $StateFile = Join-Path $Root 'bootstrap.json' function Say($m, $c = 'Gray') { Write-Host " $m" -ForegroundColor $c } # ---- elevation ------------------------------------------------------------- $me = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) if (-not $me.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Say 'Please run from an ELEVATED PowerShell (Run as Administrator):' 'Red' Say ' powershell -NoProfile -ExecutionPolicy Bypass -File .\MajicNode.ps1' 'DarkGray' exit 1 } New-Item -ItemType Directory -Force -Path $CacheDir | Out-Null # ---- read remote manifest -------------------------------------------------- $manifestUrl = "$Channel/version.json" Say "Checking for the latest MAJIC node build..." 'Cyan' try { $manifest = Invoke-RestMethod -Uri $manifestUrl -TimeoutSec 30 } catch { Say "Could not reach $manifestUrl : $($_.Exception.Message)" 'Red' exit 2 } $remoteVer = [string]$manifest.version Say "Latest version: $remoteVer" 'Green' # ---- compare to installed version ------------------------------------------ $installedVer = '' if (Test-Path $StateFile) { try { $installedVer = [string]((Get-Content -Raw $StateFile | ConvertFrom-Json).version) } catch {} } $isFresh = [string]::IsNullOrEmpty($installedVer) if (-not $isFresh) { Say "Installed version: $installedVer" 'Gray' } if ($Update -and ($installedVer -eq $remoteVer)) { Say "Already up to date ($remoteVer). Nothing to do." 'Green' exit 0 } # ---- download payload (verify sha256) -------------------------------------- Say "Downloading node payload..." 'Cyan' foreach ($f in $manifest.payload) { $dest = Join-Path $CacheDir $f.name $url = "$($manifest.base_url)/$($f.name)" Invoke-WebRequest -Uri $url -OutFile $dest -TimeoutSec 120 -UseBasicParsing if ($f.sha256) { $got = (Get-FileHash -Algorithm SHA256 -LiteralPath $dest).Hash.ToLower() if ($got -ne ([string]$f.sha256).ToLower()) { Say "Checksum mismatch on $($f.name) - aborting (got $got)." 'Red'; exit 3 } } Say " $($f.name) ok" 'DarkGray' } # ---- run the real installer (it is idempotent: install OR update) ---------- $entry = Join-Path $CacheDir $manifest.entry $instArgs = @{} if ($Email) { $instArgs['Email'] = $Email } if ($Password) { $instArgs['Password'] = $Password } if ($Update) { $instArgs['Silent'] = $true } # unattended updates: no prompts Say "$(if($isFresh){'Installing'}else{'Updating'}) the MAJIC media node..." 'Cyan' & $entry @instArgs $code = $LASTEXITCODE if ($null -eq $code) { $code = 0 } # ---- record installed version + register the auto-updater ------------------ if ($code -eq 0 -or $code -eq 1) { @{ version = $remoteVer; channel = $Channel; updatedAt = (Get-Date).ToUniversalTime().ToString('o') } | ConvertTo-Json | Set-Content -LiteralPath $StateFile -Encoding UTF8 # Copy THIS bootstrap to the install root so the updater always has it. $selfDest = Join-Path $Root 'MajicNode.ps1' try { Copy-Item $PSCommandPath $selfDest -Force } catch {} # Daily silent auto-update task (update-not-duplicate; checks manifest, no prompts). $updTask = 'MajicNodeAutoUpdate' $exists = $false try { schtasks /Query /TN $updTask >$null 2>&1; if ($LASTEXITCODE -eq 0) { $exists = $true } } catch {} $tr = "powershell -NoProfile -ExecutionPolicy Bypass -File `"$selfDest`" -Update" if ($exists) { schtasks /Change /TN $updTask /TR $tr >$null 2>&1 } else { schtasks /Create /TN $updTask /SC DAILY /ST 04:30 /RU SYSTEM /RL HIGHEST /TR $tr /F >$null 2>&1 } Say "Auto-update scheduled (daily). Re-running this file always updates - never duplicates." 'Green' } Write-Host '' if ($code -eq 0) { Say "Done - your node is on the latest build ($remoteVer)." 'Green' } elseif ($code -eq 1) { Say "Node updated but not fully online yet - see the installer notes above." 'Yellow' } else { Say "Installer exited with code $code - see output above." 'Yellow' } exit $code