|
1 | 1 | #Requires -Version 5.1 |
2 | 2 |
|
| 3 | +& { |
| 4 | +$DirectFileInvocation = -not [string]::IsNullOrWhiteSpace($PSCommandPath) |
| 5 | +$InstallerFailed = $false |
3 | 6 | $ErrorActionPreference = 'Stop' |
4 | 7 | Set-StrictMode -Version 2 |
5 | 8 |
|
6 | 9 | # PowerShell 5.1 otherwise uses a legacy code page when stdout/stderr is |
7 | 10 | # redirected, corrupting Korean output consumed by CI and automation. |
8 | | -$script:Utf8NoBom = New-Object System.Text.UTF8Encoding($false) |
9 | | -[Console]::OutputEncoding = $script:Utf8NoBom |
10 | | -$OutputEncoding = $script:Utf8NoBom |
| 11 | +$OriginalConsoleOutputEncoding = [Console]::OutputEncoding |
| 12 | +$Utf8NoBom = New-Object System.Text.UTF8Encoding($false) |
| 13 | +[Console]::OutputEncoding = $Utf8NoBom |
| 14 | +$OutputEncoding = $Utf8NoBom |
11 | 15 |
|
12 | | -$script:OriginalProgressPreference = $ProgressPreference |
| 16 | +$OriginalProgressPreference = $ProgressPreference |
13 | 17 | $ProgressPreference = 'SilentlyContinue' |
14 | 18 |
|
15 | 19 | $requestedLanguage = [Environment]::GetEnvironmentVariable('CONTEXA_LANG') |
16 | 20 | if ([string]::IsNullOrWhiteSpace($requestedLanguage)) { |
17 | 21 | $requestedLanguage = [System.Globalization.CultureInfo]::CurrentUICulture.TwoLetterISOLanguageName |
18 | 22 | } |
19 | | -$script:InstallerLanguage = if ($requestedLanguage -match '^(?i:ko)(?:[-_].*)?$') { 'ko' } else { 'en' } |
| 23 | +$InstallerLanguage = if ($requestedLanguage -match '^(?i:ko)(?:[-_].*)?$') { 'ko' } else { 'en' } |
20 | 24 |
|
21 | 25 | function Select-InstallerText { |
22 | 26 | param([string]$English, [string]$KoreanUtf8Base64) |
23 | | - if ($script:InstallerLanguage -eq 'ko') { |
| 27 | + if ($InstallerLanguage -eq 'ko') { |
24 | 28 | return [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($KoreanUtf8Base64)) |
25 | 29 | } |
26 | 30 | return $English |
27 | 31 | } |
28 | 32 |
|
29 | | -$script:Repository = 'contexa-security/contexa-cli' |
30 | | -$script:DefaultChannelManifestUrl = 'https://raw.githubusercontent.com/contexa-security/contexa-cli/snapshot-channel/channel-manifest.json' |
31 | | -$script:DefaultChannelSignatureUrl = 'https://raw.githubusercontent.com/contexa-security/contexa-cli/snapshot-channel/channel-manifest.json.sig' |
32 | | -$script:DefaultDownloadBase = 'https://github.com/contexa-security/contexa-cli/releases/download' |
33 | | -$script:PublicKeyXml = '<RSAKeyValue><Modulus>osHQvVy9S+AGAvskLk13njD9SoRHMURAbU2RQWZgQt2t0vN3Ib7aVMIwStGdJhaDIuPHTg0WrwM6ogPDDqfFmHHm8XkviBHnkgFQWvovLHtRudSgU6g+5ReaT0G0HsWFC3aGVJhOEwo5EqJJxZgjIc533CJTyn6ZbV8C0PGPP3kZQb1C/zPCaVtQg02v3Vm1C+sivBfCFRRJlcXhfc5hvbtB40DcRFkJfkBbdHBwdAnRfuH8OnIeL9dWEFyNgR7ZIREnjqNahtZbUM9gBS1p1Zw3ffTls2QSyMvQobqwNOdfP2/LN0K8uiJJ8K7nh524wGANdTlmKY2cAAkUbZsO2FK7sLCcVDXShQptXFj31DEzdQCb9hAnarXK5C6qBFxloDGzV8b+xlALFQBIO8xwXlxR8jZq+CiVJmWHUr78A0fubstaBUSgpU1ZzdUl0plI6MczU/udM7miH/O1ih7t0ox745ahU/7eXEYOLNRAJs2gidol7m+apyY/qV7DIMhz</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>' |
| 33 | +$Repository = 'contexa-security/contexa-cli' |
| 34 | +$DefaultChannelManifestUrl = 'https://raw.githubusercontent.com/contexa-security/contexa-cli/snapshot-channel/channel-manifest.json' |
| 35 | +$DefaultChannelSignatureUrl = 'https://raw.githubusercontent.com/contexa-security/contexa-cli/snapshot-channel/channel-manifest.json.sig' |
| 36 | +$DefaultDownloadBase = 'https://github.com/contexa-security/contexa-cli/releases/download' |
| 37 | +$PublicKeyXml = '<RSAKeyValue><Modulus>osHQvVy9S+AGAvskLk13njD9SoRHMURAbU2RQWZgQt2t0vN3Ib7aVMIwStGdJhaDIuPHTg0WrwM6ogPDDqfFmHHm8XkviBHnkgFQWvovLHtRudSgU6g+5ReaT0G0HsWFC3aGVJhOEwo5EqJJxZgjIc533CJTyn6ZbV8C0PGPP3kZQb1C/zPCaVtQg02v3Vm1C+sivBfCFRRJlcXhfc5hvbtB40DcRFkJfkBbdHBwdAnRfuH8OnIeL9dWEFyNgR7ZIREnjqNahtZbUM9gBS1p1Zw3ffTls2QSyMvQobqwNOdfP2/LN0K8uiJJ8K7nh524wGANdTlmKY2cAAkUbZsO2FK7sLCcVDXShQptXFj31DEzdQCb9hAnarXK5C6qBFxloDGzV8b+xlALFQBIO8xwXlxR8jZq+CiVJmWHUr78A0fubstaBUSgpU1ZzdUl0plI6MczU/udM7miH/O1ih7t0ox745ahU/7eXEYOLNRAJs2gidol7m+apyY/qV7DIMhz</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>' |
34 | 38 |
|
35 | 39 | function Get-PositiveIntEnvironment { |
36 | 40 | param([string]$Name, [int]$DefaultValue, [int]$Maximum) |
@@ -184,7 +188,7 @@ function Convert-BytesToText { |
184 | 188 | function Get-TrustedPublicKeyXml { |
185 | 189 | param([string]$DownloadBase) |
186 | 190 | if ([string]::IsNullOrWhiteSpace($env:CONTEXA_TRUSTED_PUBLIC_KEY_XML)) { |
187 | | - return $script:PublicKeyXml |
| 191 | + return $PublicKeyXml |
188 | 192 | } |
189 | 193 | $uri = [Uri]$DownloadBase |
190 | 194 | if (-not $uri.IsLoopback) { |
@@ -226,10 +230,10 @@ function Get-TargetRelease { |
226 | 230 | } |
227 | 231 |
|
228 | 232 | $manifestUrl = if ([string]::IsNullOrWhiteSpace($env:CONTEXA_CHANNEL_MANIFEST_URL)) { |
229 | | - $script:DefaultChannelManifestUrl |
| 233 | + $DefaultChannelManifestUrl |
230 | 234 | } else { $env:CONTEXA_CHANNEL_MANIFEST_URL.Trim() } |
231 | 235 | $signatureUrl = if ([string]::IsNullOrWhiteSpace($env:CONTEXA_CHANNEL_SIGNATURE_URL)) { |
232 | | - $script:DefaultChannelSignatureUrl |
| 236 | + $DefaultChannelSignatureUrl |
233 | 237 | } else { $env:CONTEXA_CHANNEL_SIGNATURE_URL.Trim() } |
234 | 238 | $manifestBytes = Invoke-BoundedDownload $manifestUrl |
235 | 239 | $signatureBytes = Invoke-BoundedDownload $signatureUrl |
@@ -526,7 +530,7 @@ function Invoke-ContexaInstaller { |
526 | 530 | } |
527 | 531 |
|
528 | 532 | Write-Host (' ' + (Select-InstallerText 'Starting Contexa CLI installation.' 'Q29udGV4YSBDTEkg7ISk7LmY66W8IOyLnOyeke2VqeuLiOuLpC4=')) |
529 | | - $downloadBase = if ([string]::IsNullOrWhiteSpace($env:CONTEXA_RELEASE_DOWNLOAD_BASE)) { $script:DefaultDownloadBase } else { $env:CONTEXA_RELEASE_DOWNLOAD_BASE.TrimEnd('/') } |
| 533 | + $downloadBase = if ([string]::IsNullOrWhiteSpace($env:CONTEXA_RELEASE_DOWNLOAD_BASE)) { $DefaultDownloadBase } else { $env:CONTEXA_RELEASE_DOWNLOAD_BASE.TrimEnd('/') } |
530 | 534 | $targetRelease = Get-TargetRelease $downloadBase |
531 | 535 | $version = $targetRelease.ReleaseTag |
532 | 536 | $expectedCliVersion = $targetRelease.CliVersion |
@@ -656,24 +660,32 @@ function Invoke-ContexaInstaller { |
656 | 660 |
|
657 | 661 | try { |
658 | 662 | Invoke-ContexaInstaller |
659 | | - exit 0 |
660 | 663 | } catch { |
| 664 | + $InstallerFailed = $true |
661 | 665 | $failureCode = 'INSTALLER_OPERATION_FAILED' |
662 | 666 | if ($_.Exception.Message -match '\[([A-Z][A-Z0-9_]+)\]') { |
663 | 667 | $failureCode = $Matches[1] |
664 | 668 | } |
665 | | - if ($script:InstallerLanguage -eq 'ko') { |
666 | | - [Console]::Error.WriteLine( |
| 669 | + if ($InstallerLanguage -eq 'ko') { |
| 670 | + $failureSummary = |
667 | 671 | 'Contexa ' + |
668 | 672 | (Select-InstallerText 'installer failed [' '7ISk7LmYIO2UhOuhnOq3uOueqCDsi6TtjKggWw==') + |
669 | 673 | $failureCode + |
670 | 674 | (Select-InstallerText ']: Check the error code, fix the cause, and run the same command again.' 'XTog7Jik66WYIOy9lOuTnOulvCDtmZXsnbjtlZjqs6Ag7JuQ7J247J2EIOyImOygle2VnCDrkqQg6rCZ7J2AIOuqheugueydhCDri6Tsi5wg7Iuk7ZaJ7ZWY7IS47JqULg==') |
671 | | - ) |
672 | 675 | } else { |
673 | | - [Console]::Error.WriteLine('Contexa installer failed [' + $failureCode + ']: ' + $_.Exception.Message) |
674 | | - } |
675 | | - [Console]::Error.WriteLine((Select-InstallerText 'The existing CLI was preserved when possible. Fix the reported cause and run the same command again.' '6rCA64ql7ZWcIOqyveyasCDquLDsobQgQ0xJ66W8IOuztOyhtO2WiOyKteuLiOuLpC4g67O06rOg65CcIOybkOyduOydhCDtlbTqsrDtlZwg65KkIOqwmeydgCDrqoXroLnsnYQg64uk7IucIOyLpO2Wie2VmOyEuOyalC4=')) |
676 | | - exit 1 |
| 676 | + $failureSummary = 'Contexa installer failed [' + $failureCode + ']: ' + $_.Exception.Message |
| 677 | + } |
| 678 | + $preservationMessage = Select-InstallerText 'The existing CLI was preserved when possible. Fix the reported cause and run the same command again.' '6rCA64ql7ZWcIOqyveyasCDquLDsobQgQ0xJ66W8IOuztOyhtO2WiOyKteuLiOuLpC4g67O06rOg65CcIOybkOyduOydhCDtlbTqsrDtlZwg65KkIOqwmeydgCDrqoXroLnsnYQg64uk7IucIOyLpO2Wie2VmOyEuOyalC4=' |
| 679 | + [Console]::Error.WriteLine($failureSummary) |
| 680 | + [Console]::Error.WriteLine($preservationMessage) |
| 681 | + throw [System.InvalidOperationException]::new( |
| 682 | + ('Contexa installer failed [' + $failureCode + '].'), |
| 683 | + $_.Exception |
| 684 | + ) |
677 | 685 | } finally { |
678 | | - $ProgressPreference = $script:OriginalProgressPreference |
| 686 | + $ProgressPreference = $OriginalProgressPreference |
| 687 | + if (-not $InstallerFailed -or -not $DirectFileInvocation) { |
| 688 | + [Console]::OutputEncoding = $OriginalConsoleOutputEncoding |
| 689 | + } |
| 690 | +} |
679 | 691 | } |
0 commit comments