[CmdletBinding()] param( [switch]$Compile ) $ErrorActionPreference = 'Stop' $workspace = Split-Path -Parent $MyInvocation.MyCommand.Path $launcherDir = Join-Path $workspace 'mikrotik\launcher' $issPath = Join-Path $workspace 'NetworkCustomers_latest.iss' if ($Compile) { $csc = 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe' if (-not (Test-Path -LiteralPath $csc)) { throw 'The .NET Framework C# compiler was not found.' } $launcherSource = Join-Path $launcherDir 'AgentPortalLauncher.cs' $updateSource = Join-Path $launcherDir 'ClientUpdateManager.cs' $launcherOutput = Join-Path $launcherDir 'AgentPortalLauncher.final.exe' $compilerArgs = @( '/nologo', '/target:winexe', '/platform:x86', '/optimize+', ('/win32icon:' + (Join-Path $launcherDir 'NetworkCustomers.ico')), ('/out:' + $launcherOutput), '/reference:System.dll', '/reference:System.Core.dll', '/reference:System.Drawing.dll', '/reference:System.Windows.Forms.dll', '/reference:System.Web.Extensions.dll', '/reference:System.IO.Compression.dll', '/reference:System.IO.Compression.FileSystem.dll', ('/reference:' + (Join-Path $launcherDir 'Microsoft.Web.WebView2.Core.dll')), ('/reference:' + (Join-Path $launcherDir 'Microsoft.Web.WebView2.WinForms.dll')), $launcherSource, $updateSource ) & $csc @compilerArgs if ($LASTEXITCODE -ne 0) { throw "Launcher compilation failed with exit code $LASTEXITCODE" } Copy-Item -LiteralPath $launcherOutput -Destination (Join-Path $launcherDir 'AgentPortalLauncher.exe') -Force Write-Host 'Desktop launcher compiled explicitly for x86.' -ForegroundColor Green $versionText = Get-Content -LiteralPath (Join-Path $workspace 'mikrotik\admin\version.php') -Raw $versionMatch = [regex]::Match($versionText, "'version'\s*=>\s*'([^']+)'", 'IgnoreCase') if (-not $versionMatch.Success) { throw 'Unable to read the application version.' } $clientPackageBuilder = Join-Path $workspace 'build_linked_client_update.ps1' $releaseVersion = $versionMatch.Groups[1].Value # 1.3.0 is the updater-capable foundation. Every later package is a # cumulative delta against this fixed baseline, so a client may safely skip # intermediate releases and still jump directly to the newest version. $foundationVersion = '1.3.0' $foundationBaseline = Join-Path $workspace ('mikrotik\admin\updates\distributed\baselines\' + $foundationVersion + '.json') $packageArgs = @{ Version = $releaseVersion; MinVersion = '1.2.9'; ReleaseId = ('desktop-' + $releaseVersion) } if ($releaseVersion -ne $foundationVersion -and (Test-Path -LiteralPath $foundationBaseline)) { $packageArgs.MinVersion = $foundationVersion $packageArgs.BaselineManifest = $foundationBaseline } & $clientPackageBuilder @packageArgs } function Get-PeArchitecture([string]$Path) { if (-not (Test-Path -LiteralPath $Path)) { throw "Missing required runtime file: $Path" } $bytes = [IO.File]::ReadAllBytes($Path) if ($bytes.Length -lt 64) { throw "Invalid PE file: $Path" } $peOffset = [BitConverter]::ToInt32($bytes, 0x3c) if ($peOffset -lt 0 -or ($peOffset + 6) -ge $bytes.Length) { throw "Invalid PE header: $Path" } $machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4) switch ($machine) { 0x014c { return 'x86' } 0x8664 { return 'x64' } 0xaa64 { return 'arm64' } default { return ('unknown-0x{0:X4}' -f $machine) } } } $runtimeFiles = @( (Join-Path $launcherDir 'AgentPortalLauncher.final.exe'), (Join-Path $launcherDir 'OutputDeviceAgent.x86.exe'), (Join-Path $launcherDir 'WebView2Loader.dll') ) $architectures = foreach ($file in $runtimeFiles) { [PSCustomObject]@{ File = [IO.Path]::GetFileName($file) Architecture = Get-PeArchitecture $file } } $wrong = @($architectures | Where-Object Architecture -ne 'x86') if ($wrong.Count -gt 0) { $details = ($wrong | ForEach-Object { "$($_.File)=$($_.Architecture)" }) -join ', ' throw "The desktop runtime must be entirely x86. Found: $details" } $architectures | Format-Table -AutoSize Write-Host 'Desktop runtime architecture check passed.' -ForegroundColor Green if ($Compile) { $isccCandidates = @( 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe', 'C:\Program Files\Inno Setup 6\ISCC.exe' ) $iscc = $isccCandidates | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1 if (-not $iscc) { throw 'Inno Setup 6 compiler was not found.' } & $iscc $issPath if ($LASTEXITCODE -ne 0) { throw "Inno Setup failed with exit code $LASTEXITCODE" } }