# JustASRV updater installer for Windows. Run in an elevated PowerShell: # Invoke-WebRequest https://docs.justasrv.com/downloads/Install-JustASRV.ps1 -OutFile Install-JustASRV.ps1 # .\Install-JustASRV.ps1 -Hostname acme-main.ddns.justasrv.com # The token is prompted for securely (or pass -Token for unattended RMM deployment). # Uninstall: .\Install-JustASRV.ps1 -Uninstall param( [string]$Hostname, [string]$Token, [switch]$Uninstall ) $ErrorActionPreference = 'Stop' $Dir = Join-Path $env:ProgramData 'JustASRV' $Script = Join-Path $Dir 'JustASRV-Update.ps1' $TaskName = 'JustASRV DDNS Updater' $principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw 'Run this from an elevated (Administrator) PowerShell.' } if ($Uninstall) { Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue Remove-Item -Recurse -Force $Dir -ErrorAction SilentlyContinue Write-Host 'JustASRV updater removed.' return } if (-not $Hostname) { $Hostname = (Read-Host 'Hostname (e.g. acme-main.ddns.justasrv.com)').Trim().ToLower() } if ($Hostname -notmatch '^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.ddns\.justasrv\.com$') { throw 'Usage: .\Install-JustASRV.ps1 -Hostname .ddns.justasrv.com' } if (-not $Token) { $secure = Read-Host -AsSecureString "Token for $Hostname" $Token = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)) } if ($Token -notmatch '^jas_[A-Za-z0-9]{20,}$') { throw 'That does not look like a JustASRV token (jas_...).' } # Folder readable only by SYSTEM and Administrators. New-Item -ItemType Directory -Force -Path $Dir | Out-Null $acl = New-Object Security.AccessControl.DirectorySecurity $acl.SetAccessRuleProtection($true, $false) foreach ($sid in 'S-1-5-18', 'S-1-5-32-544') { $id = New-Object Security.Principal.SecurityIdentifier($sid) $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($id, 'FullControl', 'ContainerInherit,ObjectInherit', 'None', 'Allow'))) } Set-Acl -Path $Dir -AclObject $acl [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -UseBasicParsing -Uri 'https://docs.justasrv.com/downloads/JustASRV-Update.ps1' -OutFile $Script if (-not (Select-String -Path $Script -Pattern 'JustASRV DDNS updater' -Quiet)) { throw 'Download of the updater failed.' } Add-Type -AssemblyName System.Security $protected = [Security.Cryptography.ProtectedData]::Protect([Text.Encoding]::UTF8.GetBytes($Token), $null, 'LocalMachine') @{ Hostname = $Hostname; TokenProtected = [Convert]::ToBase64String($protected); Server = 'https://ddns.justasrv.com'; RefreshSeconds = 600 } | ConvertTo-Json | Set-Content -Path (Join-Path $Dir 'config.json') -Encoding ASCII Remove-Item (Join-Path $Dir 'state.json') -ErrorAction SilentlyContinue # new token: clear any backoff $action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$Script`"" $triggers = @( (New-ScheduledTaskTrigger -AtStartup), (New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) -RepetitionInterval (New-TimeSpan -Minutes 2)) ) $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable ` -ExecutionTimeLimit (New-TimeSpan -Minutes 2) -MultipleInstances IgnoreNew $principalTask = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest Register-ScheduledTask -TaskName $TaskName -Action $action -Trigger $triggers -Settings $settings -Principal $principalTask -Force | Out-Null Start-ScheduledTask -TaskName $TaskName Start-Sleep -Seconds 8 Write-Host "Installed. Task: '$TaskName' (every 2 minutes, as SYSTEM)." Write-Host "Log: $Dir\justasrv.log" if (Test-Path (Join-Path $Dir 'justasrv.log')) { Get-Content (Join-Path $Dir 'justasrv.log') -Tail 3 }