# microManager installer for Windows (x64). In PowerShell: # # irm https://micromanager.win/install.ps1 | iex # # What it does, in order: # 1. reads the release manifest (latest.yml) and downloads the installer it names, # 2. checks the installer's SHA-512 against the manifest and stops if they differ, # 3. runs it for your user only (no administrator rights), which installs microManager under # %LOCALAPPDATA%\Programs and adds it to the Start menu, # 4. removes the downloaded installer. # The app updates itself from then on. # # Settings (environment variables, for example: $env:MICROMANAGER_SILENT = '1'; irm ... | iex): # MICROMANAGER_SILENT=1 install without showing the installer's progress window # MICROMANAGER_NO_RUN=1 only download and check the installer, into the current folder # (works on any system with PowerShell) # MICROMANAGER_BASE_URL=https://... release server (default https://micromanager.win) # # Everything runs inside Install-MicroManager, called on the last line, so a partly downloaded copy # of this script does nothing. function Install-MicroManager { $ErrorActionPreference = 'Stop' Set-StrictMode -Version 3.0 # Invoke-WebRequest's progress bar slows downloads in Windows PowerShell 5.1 by orders of magnitude. $ProgressPreference = 'SilentlyContinue' function Say([string] $message) { Write-Host "microManager: $message" } # The reason goes out as one plain line (PowerShell wraps and decorates error records), then the throw stops the # script without closing the window `irm | iex` runs in. function Fail([string] $message) { Write-Host "microManager: error: $message" throw 'microManager: stopped; see the error above.' } function Get-Setting([string] $name) { $value = [Environment]::GetEnvironmentVariable($name) if ($null -eq $value) { return '' } return $value } function Save-Url([string] $url, [string] $path) { try { Invoke-WebRequest -Uri $url -OutFile $path -UseBasicParsing } catch { Fail "could not download ${url}: $($_.Exception.Message)" } } # electron-builder writes each file's SHA-512 in base64. function Get-Sha512Base64([string] $path) { $stream = [System.IO.File]::OpenRead($path) $sha = [System.Security.Cryptography.SHA512]::Create() try { return [Convert]::ToBase64String($sha.ComputeHash($stream)) } finally { $sha.Dispose() $stream.Dispose() } } # The version and the installer's file name and SHA-512 from latest.yml. function Read-Manifest([string] $text) { $version = '' $files = New-Object System.Collections.Generic.List[object] $url = '' foreach ($rawLine in ($text -split "`n")) { $line = $rawLine.TrimEnd("`r", ' ', "`t") if ($line -match '^version:\s*(.+)$') { $version = $Matches[1].Trim().Trim('"', "'") } elseif ($line -match '^\s*-\s*url:\s*(.+)$') { $url = $Matches[1].Trim().Trim('"', "'") } elseif ($url -and $line -match '^\s*sha512:\s*(.+)$') { $files.Add([pscustomobject] @{ Url = $url; Sha512 = $Matches[1].Trim().Trim('"', "'") }) $url = '' } } $installer = $files | Where-Object { $_.Url -like '*.exe' } | Select-Object -First 1 return [pscustomobject] @{ Version = $version; Installer = $installer } } $noRun = (Get-Setting 'MICROMANAGER_NO_RUN') -eq '1' # Windows PowerShell (5.1) only runs on Windows; PowerShell 6 and later say where they run. $isCore = $PSVersionTable.PSVersion.Major -ge 6 $runningOnWindows = (-not $isCore) -or $IsWindows if (-not $noRun) { if (-not $runningOnWindows) { Fail 'this installer is for Windows; on macOS and Linux run: curl -fsSL https://micromanager.win/install.sh | sh' } $arch = $env:PROCESSOR_ARCHITEW6432 if (-not $arch) { $arch = $env:PROCESSOR_ARCHITECTURE } if ($arch -ne 'AMD64') { Fail "there is no microManager build for $arch Windows yet (x64 only). See https://micromanager.win/install#windows" } } $baseUrl = Get-Setting 'MICROMANAGER_BASE_URL' if (-not $baseUrl) { $baseUrl = 'https://micromanager.win' } $baseUrl = $baseUrl.TrimEnd('/') if ($baseUrl -notmatch '^https://' -and $baseUrl -notmatch '^http://(127\.0\.0\.1|localhost):\d+$') { Fail 'MICROMANAGER_BASE_URL must be an https:// URL.' } if (-not $isCore) { # Windows PowerShell 5.1 may still default to TLS 1.0. [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } $releasesUrl = "$baseUrl/releases/win" $workDir = Join-Path ([System.IO.Path]::GetTempPath()) ("micromanager-install-" + [Guid]::NewGuid().ToString('N')) New-Item -ItemType Directory -Path $workDir | Out-Null try { Say 'checking the newest release for Windows' $manifestPath = Join-Path $workDir 'latest.yml' Save-Url "$releasesUrl/latest.yml" $manifestPath $manifest = Read-Manifest ([System.IO.File]::ReadAllText($manifestPath)) if (-not $manifest.Version) { Fail 'the release manifest has no version.' } if (-not $manifest.Installer) { Fail "version $($manifest.Version) has no Windows installer yet. See https://micromanager.win/install#windows" } $fileName = $manifest.Installer.Url if ($fileName -notmatch '^[A-Za-z0-9][A-Za-z0-9._-]*\.exe$') { Fail "unexpected file name in the release manifest: $fileName" } Say "downloading microManager $($manifest.Version)" $installer = Join-Path $workDir $fileName Save-Url "$releasesUrl/$fileName" $installer if ((Get-Sha512Base64 $installer) -ne $manifest.Installer.Sha512) { Fail "the download's SHA-512 does not match the release manifest; nothing was installed." } Say 'checksum verified' if ($noRun) { $kept = Join-Path (Get-Location).ProviderPath $fileName Move-Item -LiteralPath $installer -Destination $kept -Force Say "saved the checked installer as $kept; run it when you are ready." return } Say "installing microManager $($manifest.Version) for $env:USERNAME" if ((Get-Setting 'MICROMANAGER_SILENT') -eq '1') { $process = Start-Process -FilePath $installer -ArgumentList '/S' -Wait -PassThru } else { $process = Start-Process -FilePath $installer -Wait -PassThru } if ($process.ExitCode -ne 0) { Fail "the installer stopped with exit code $($process.ExitCode)." } Say "installed microManager $($manifest.Version). Open it from the Start menu." } finally { Remove-Item -LiteralPath $workDir -Recurse -Force -ErrorAction SilentlyContinue } } Install-MicroManager