# ITX Quick Run bootstrap $ErrorActionPreference = 'Stop' if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Host 'Run this from an elevated PowerShell (Run as Administrator).' -ForegroundColor Red; return } if ($PSVersionTable.PSVersion.Major -lt 5) { Write-Host 'PowerShell 5.1 or later is required.' -ForegroundColor Red; return } [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $bios = Get-CimInstance Win32_BIOS; $cs = Get-CimInstance Win32_ComputerSystem $fp = @{ hostname = $env:COMPUTERNAME; serial = $bios.SerialNumber; manufacturer = $cs.Manufacturer; model = $cs.Model; os_version = [string][Environment]::OSVersion.Version } Write-Host ''; Write-Host ' ITX Quick Run' -ForegroundColor Cyan; Write-Host (" " + $env:COMPUTERNAME) -ForegroundColor DarkGray; Write-Host '' function Read-DeploymentPin { # Masked input first. When the script arrives through "irm ... | iex" some # hosts hand Read-Host a console that never receives the keystrokes, so the # SecureString comes back empty; fall back to a visible prompt rather than # silently send nothing. PtrToStringBSTR is the correct marshal for a BSTR, # and ZeroFreeBSTR wipes the copy afterwards. $sec = Read-Host ' Enter deployment PIN' -AsSecureString $value = '' if ($sec -and $sec.Length -gt 0) { $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec) try { $value = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) } finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } } if ([string]::IsNullOrWhiteSpace($value)) { Write-Host ' (masked entry did not register - type it here)' -ForegroundColor DarkGray $value = Read-Host ' Enter deployment PIN' } return $value } for ($try = 1; $try -le 3; $try++) { $entered = Read-DeploymentPin # Normalise locally and check the shape before spending a server attempt: # a mistyped PIN should cost nothing and say so immediately. $pin = ($entered -replace '\D', '') $entered = $null if ($pin.Length -ne 8) { Write-Host (" That is " + $pin.Length + " digit(s); the PIN is 8 digits (e.g. 1234-5678).") -ForegroundColor Yellow $pin = $null if ($try -eq 3) { Write-Host ' Too many failed attempts.' -ForegroundColor Red; return } continue } try { $resp = Invoke-RestMethod -Method Post -Uri 'https://medhillnukxymmtwdpcu.supabase.co/functions/v1/quick-run-redeem' -ContentType 'application/json' -Body (@{ pin = $pin; fingerprint = $fp } | ConvertTo-Json -Compress) -TimeoutSec 120 } catch { $resp = $null if ($_.Exception.Response.StatusCode.value__ -eq 429) { Write-Host ' Too many attempts. Wait a few minutes and try again.' -ForegroundColor Red; return } Write-Host (" Could not reach the portal: " + $_.Exception.Message) -ForegroundColor Red; return } finally { $pin = $null; [GC]::Collect() } if ($resp.script) { break } Write-Host (" " + $resp.error) -ForegroundColor Red if ($try -eq 3) { Write-Host ' Too many failed attempts.' -ForegroundColor Red; return } } $path = Join-Path $env:TEMP ('itx-quickrun-' + $resp.machine_id + '.ps1') # Always run the provisioning script in 64-bit PowerShell. Get-LocalUser and the # rest of Microsoft.PowerShell.LocalAccounts do not exist in the 32-bit host, and # a tech launching "Windows PowerShell (x86)" from the Start menu is easy to do — # it cost a whole run with "The term 'Get-LocalUser' is not recognized". SysNative # is the alias that lets a 32-bit process reach the real System32; it does not # exist for a 64-bit process, hence the branch. This also gives the inventory the # unredirected registry view. $psExe = Join-Path $env:WINDIR 'System32\WindowsPowerShell\v1.0\powershell.exe' if (-not [Environment]::Is64BitProcess -and [Environment]::Is64BitOperatingSystem) { $native = Join-Path $env:WINDIR 'SysNative\WindowsPowerShell\v1.0\powershell.exe' if (Test-Path $native) { $psExe = $native Write-Host ' (relaunching in 64-bit PowerShell)' -ForegroundColor DarkGray } } try { Set-Content -Path $path -Value $resp.script -Encoding UTF8 & $psExe -ExecutionPolicy Bypass -NoProfile -File $path } finally { Remove-Item $path -Force -ErrorAction SilentlyContinue }