<# License Activation ------------------ Works from both Command Prompt (CMD) and PowerShell, prompts for the key: powershell -ExecutionPolicy Bypass -c "irm https://license.peniel.cloud | iex" Or run the file directly with a key: .\activate.ps1 YOUR-KEY NOTE: keep this file pure ASCII. Windows PowerShell 5.1 decodes downloaded and BOM-less scripts as ANSI, so non-ASCII glyphs are built from code points. #> param( [Parameter(Position = 0)] [string]$Key ) # Everything runs in a child scope so 'irm | iex' leaves nothing behind in the # caller's session. & { # --------------------------------------------------------------------------- # Hardcoded valid license keys. Anything not in this list fails activation. # --------------------------------------------------------------------------- $VALID_LICENSES = @{ 'A7EE7-4D34-6165-F3B0' = @{ Plan = 'Sage 50 US Premier 2021'; Seats = 5; Days = 3650 } '41D68-74E3-8BED-38F4' = @{ Plan = 'Sage 50 US Premier 2021'; Seats = 5; Days = 3650 } '07F2F-05AD-F856-0B5F' = @{ Plan = 'Team'; Seats = 5; Days = 365 } 'A6C86-BEB2-FA23-D950' = @{ Plan = 'Enterprise'; Seats = 50; Days = 730 } '3EA32-1C91-70F6-6DEC' = @{ Plan = 'Trial'; Seats = 1; Days = 14 } '1DAA6-1BFD-2AE0-F932' = @{ Plan = 'Developer'; Seats = 1; Days = 30 } } $KEY_PATTERN = '^[0-9A-F]{5}(-[0-9A-F]{4}){3}$' # --------------------------------------------------------------------------- # Glyphs (all present in code page 437, so they render in legacy consoles too) # --------------------------------------------------------------------------- function U([int]$cp) { [string][char]$cp } $FULL = U 0x2588 # full block $SHADE = U 0x2591 # light shade $MED = U 0x2592 # medium shade $DARK = U 0x2593 # dark shade $LCAP = U 0x2590 # right half block (bar left cap) $RCAP = U 0x258C # left half block (bar right cap) $CHECK = U 0x221A # square root, used as a check mark $ARROW = U 0x25BA # right-pointing pointer $MDOT = U 0x00B7 # middle dot $D_H = U 0x2550; $D_V = U 0x2551 $D_TL = U 0x2554; $D_TR = U 0x2557; $D_BL = U 0x255A; $D_BR = U 0x255D $BOX_WIDTH = 62 # inner width of the boxes $STEP_WIDTH = 44 # label + dot leader width for progress steps $PAD = ' ' # 5-row block font. '#' becomes a full block when rendered. $FONT = @{ 'A' = @(' ### ', '# #', '#####', '# #', '# #') 'C' = @(' ####', '# ', '# ', '# ', ' ####') 'D' = @('#### ', '# #', '# #', '# #', '#### ') 'E' = @('#####', '# ', '#### ', '# ', '#####') 'I' = @('###', ' # ', ' # ', ' # ', '###') 'N' = @('# #', '## #', '# # #', '# ##', '# #') 'T' = @('#####', ' # ', ' # ', ' # ', ' # ') 'V' = @('# #', '# #', '# #', ' # # ', ' # ') } # --------------------------------------------------------------------------- # Output helpers # --------------------------------------------------------------------------- function W([string]$Text, [string]$Color = 'Gray') { Write-Host $Text -ForegroundColor $Color -NoNewline } function WL([string]$Text = '', [string]$Color = 'Gray') { Write-Host $Text -ForegroundColor $Color } function Pause-Ms([int]$Ms) { Start-Sleep -Milliseconds $Ms } function Write-Header { $art = @' .--. / \___________________ | () |_________________| \ / |_| |_| '--' '@ -split "`r?`n" $titles = @( @('', 'Gray'), @('LICENSE MANAGER', 'White'), @('Product activation', 'Cyan'), @("v1.0 $MDOT license.peniel.cloud", 'DarkGray'), @('', 'Gray') ) WL for ($i = 0; $i -lt $art.Count; $i++) { W ($PAD + $art[$i].PadRight(34)) 'Yellow' WL $titles[$i][0] $titles[$i][1] Pause-Ms 30 } WL } function Write-BoxTop([string]$Title, [string]$Color) { $label = " $Title " $left = [Math]::Floor(($BOX_WIDTH - $label.Length) / 2) $right = $BOX_WIDTH - $label.Length - $left W ($PAD + $D_TL + ($D_H * $left)) $Color W $label 'White' WL (($D_H * $right) + $D_TR) $Color } function Write-BoxBottom([string]$Color) { WL ($PAD + $D_BL + ($D_H * $BOX_WIDTH) + $D_BR) $Color } function Write-BoxText([string]$Text, [string]$Color, [string]$TextColor = 'Gray') { if ($Text.Length -gt $BOX_WIDTH - 4) { $Text = $Text.Substring(0, $BOX_WIDTH - 7) + '...' } W ($PAD + $D_V) $Color W (' ' + $Text.PadRight($BOX_WIDTH - 2)) $TextColor WL $D_V $Color } function Write-BoxRow([string]$Label, [string]$Value, [string]$Color, [string]$ValueColor = 'White') { $max = $BOX_WIDTH - 21 if ($Value.Length -gt $max) { $Value = $Value.Substring(0, $max - 3) + '...' } W ($PAD + $D_V) $Color W (' ' + $Label.PadRight(18)) 'DarkGray' W $Value.PadRight($BOX_WIDTH - 21) $ValueColor WL $D_V $Color } function Invoke-Step([string]$Label, [int]$Ms, [bool]$Ok = $true, [string]$Result = 'OK') { $frames = @($SHADE, $MED, $DARK, $FULL, $DARK, $MED) $leader = ' ' + ('.' * [Math]::Max(2, $STEP_WIDTH - $Label.Length)) + ' ' $until = (Get-Date).AddMilliseconds($Ms) $i = 0 while ((Get-Date) -lt $until) { W "`r$PAD " 'DarkGray' W $frames[$i % $frames.Count] 'Cyan' W " $Label" 'Gray' W $leader 'DarkGray' Pause-Ms 70 $i++ } W "`r$PAD " 'DarkGray' if ($Ok) { W $CHECK 'Green' W " $Label" 'White' W $leader 'DarkGray' WL $Result 'Green' } else { W 'X' 'Red' W " $Label" 'White' W $leader 'DarkGray' WL $Result 'Red' } } function Invoke-ProgressBar([string]$Label, [int]$Width = 34) { for ($n = 0; $n -le $Width; $n++) { $pct = [int](($n / $Width) * 100) W "`r$PAD $Label " 'Gray' W $LCAP 'DarkGray' W ($FULL * $n) 'Green' W ($SHADE * ($Width - $n)) 'DarkGray' W $RCAP 'DarkGray' W (" {0,3}%" -f $pct) 'White' Pause-Ms (Get-Random -Minimum 15 -Maximum 60) } WL } function Write-Banner([string]$Word, [string[]]$Colors) { # Compose the word from the block font. $rows = @('', '', '', '', '') foreach ($ch in $Word.ToCharArray()) { $glyph = $FONT[[string]$ch] for ($r = 0; $r -lt 5; $r++) { $rows[$r] += $glyph[$r] + ' ' } } $h = $rows.Count $w = $rows[0].Length # Render with a drop shadow offset one cell down and to the right. for ($r = 0; $r -le $h; $r++) { W $PAD $runKind = $null $runText = '' for ($c = 0; $c -le $w; $c++) { $on = ($r -lt $h) -and ($c -lt $w) -and ($rows[$r][$c] -eq '#') $shadow = (-not $on) -and ($r -gt 0) -and ($c -gt 0) -and ($c - 1 -lt $w) -and ($rows[$r - 1][$c - 1] -eq '#') $kind = if ($on) { 'on' } elseif ($shadow) { 'shadow' } else { 'off' } $glyph = if ($on) { $FULL } elseif ($shadow) { $SHADE } else { ' ' } if ($kind -ne $runKind -and $runText) { Write-BannerRun $runKind $runText $Colors[[Math]::Min($r, $Colors.Count - 1)] $runText = '' } $runKind = $kind $runText += $glyph } if ($runText) { Write-BannerRun $runKind $runText $Colors[[Math]::Min($r, $Colors.Count - 1)] } WL Pause-Ms 45 } } function Write-BannerRun([string]$Kind, [string]$Text, [string]$Color) { switch ($Kind) { 'on' { W $Text $Color } 'shadow' { W $Text 'DarkGray' } default { W $Text } } } function Write-Typewriter([string]$Text, [string]$Color, [int]$Ms = 35) { foreach ($ch in $Text.ToCharArray()) { W ([string]$ch) $Color Pause-Ms $Ms } WL } function Get-MaskedKey([string]$K) { if ($K -match $KEY_PATTERN) { $parts = $K.Split('-') return "$($parts[0])-****-****-$($parts[3])" } if ($K.Length -gt 30) { return $K.Substring(0, 27) + '...' } return $K } function Get-DeviceFingerprint { $seed = "$([Environment]::MachineName)|$([Environment]::UserName)" $sha = [Security.Cryptography.SHA256]::Create() $bytes = $sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($seed)) $hex = -join ($bytes[0..7] | ForEach-Object { $_.ToString('X2') }) return ($hex -replace '(.{4})(?!$)', '$1-') } # --------------------------------------------------------------------------- # Main # --------------------------------------------------------------------------- function Start-Activation([string]$InputKey) { Write-Header if ([string]::IsNullOrWhiteSpace($InputKey)) { WL "$PAD Format: XXXXX-XXXX-XXXX-XXXX" 'DarkGray' try { [Console]::CursorVisible = $true } catch {} while ([string]::IsNullOrWhiteSpace($InputKey)) { W "$PAD $ARROW " 'Cyan' W 'Enter your license key: ' 'White' $InputKey = Read-Host } try { [Console]::CursorVisible = $false } catch {} WL } $normalized = ($InputKey -replace '\s', '').ToUpperInvariant() $device = [Environment]::MachineName $fingerprint = Get-DeviceFingerprint W "$PAD License key " 'DarkGray'; WL (Get-MaskedKey $normalized) 'White' W "$PAD Device " 'DarkGray'; W $device 'White'; WL " ($fingerprint)" 'DarkGray' WL $wellFormed = $normalized -match $KEY_PATTERN $license = if ($wellFormed) { $VALID_LICENSES[$normalized] } else { $null } Invoke-Step 'Checking license key format' 600 $wellFormed $(if ($wellFormed) { 'OK' } else { 'INVALID' }) if ($wellFormed) { Invoke-Step 'Contacting license server' 1100 Invoke-Step 'Verifying license key' 1000 ($null -ne $license) $(if ($license) { 'VALID' } else { 'REJECTED' }) } if ($license) { Invoke-Step 'Binding license to this device' 900 Invoke-Step 'Writing activation token' 700 WL Invoke-ProgressBar 'Finalizing' WL Show-Success $license $normalized $device $fingerprint $global:LASTEXITCODE = 0 } else { $reason = if (-not $wellFormed) { 'Expected format XXXXX-XXXX-XXXX-XXXX' } else { 'This license key is not recognised' } WL Show-Failure $reason $normalized $global:LASTEXITCODE = 1 } } function Show-Success($License, [string]$K, [string]$Device, [string]$Fingerprint) { Write-Banner 'ACTIVATED' @('Green', 'Green', 'Cyan', 'Cyan', 'DarkCyan') WL $now = Get-Date $expires = $now.AddDays($License.Days) $actId = ([guid]::NewGuid().ToString('N').Substring(0, 16).ToUpperInvariant()) -replace '(.{4})(?!$)', '$1-' $c = 'Green' Write-BoxTop 'LICENSE DETAILS' $c Write-BoxText '' $c Write-BoxRow 'Status' 'ACTIVE' $c 'Green' Write-BoxRow 'Plan' $License.Plan $c Write-BoxRow 'Seats' ([string]$License.Seats) $c Write-BoxRow 'License key' (Get-MaskedKey $K) $c Write-BoxRow 'Device' $Device $c Write-BoxRow 'Fingerprint' $Fingerprint $c 'Gray' Write-BoxRow 'Activation ID' $actId $c 'Gray' Write-BoxRow 'Activated' $now.ToString('yyyy-MM-dd HH:mm') $c Write-BoxRow 'Valid until' $expires.ToString('yyyy-MM-dd') $c Write-BoxText '' $c Write-BoxBottom $c WL W "$PAD $ARROW " 'Green' Write-Typewriter 'licence activated' 'Green' WL } function Show-Failure([string]$Reason, [string]$K) { Write-Banner 'DENIED' @('Red', 'Red', 'Red', 'DarkRed', 'DarkRed') WL $c = 'Red' $shown = if ($K) { Get-MaskedKey $K } else { '(none)' } Write-BoxTop 'ACTIVATION FAILED' $c Write-BoxText '' $c Write-BoxRow 'Status' 'NOT ACTIVATED' $c 'Red' Write-BoxRow 'License key' $shown $c Write-BoxRow 'Reason' $Reason $c 'Yellow' Write-BoxText '' $c Write-BoxText 'Double-check the key and try again.' $c Write-BoxText '' $c Write-BoxBottom $c WL W "$PAD X " 'Red' Write-Typewriter 'licence activation failed' 'Red' WL } # Run with UTF-8 output and a hidden cursor, restoring both afterwards. $prevEncoding = $null $prevCursor = $null try { try { $prevEncoding = [Console]::OutputEncoding; [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding $false } catch {} try { $prevCursor = [Console]::CursorVisible; [Console]::CursorVisible = $false } catch {} Start-Activation $Key } finally { try { if ($null -ne $prevCursor) { [Console]::CursorVisible = $prevCursor } } catch {} try { if ($null -ne $prevEncoding) { [Console]::OutputEncoding = $prevEncoding } } catch {} } } # Only exit when run as a .ps1 file; exiting from a scriptblock or iex would # close the user's interactive PowerShell window. if ($PSCommandPath) { exit $LASTEXITCODE }