mega-has-Install.psm1
function Install-HASInstaller { [CmdletBinding(DefaultParametersetName = "default")] param( [Parameter(Mandatory)] [String]$token, [Parameter(ParameterSetName = 'byBundle')] [ValidatePattern("^([^v:]+)[v:]([0-9\.]+)$")] [String]$bundle, [Parameter(ParameterSetName = 'byHopexVersion')] [String]$hopexVersion, [Parameter()] [switch]$includePrerelease, [Parameter()] [String]$outFile = 'has.setup.exe', [Parameter(HelpMessage = "HOPEX store address (eg. https://store.mega.com)")] [String]$server = 'https://store.mega.com' ) [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Write-Output "Downloading HAS installer..." $url = "$server/releases/latest?kind=installer&api_key=$Token" if ($bundle) { $url = $url + "&bundle=$Bundle" } if ($hopexVersion) { $url = $url + "&hopex_version=$hopexVersion" } if ($IncludePrerelease.IsPresent) { $url = $url + "&includePrerelease=1" } Write-Output " Downloading setup from '$url' ..." Invoke-WebRequest $url -OutFile $outFile Write-Output "HAS installer donwloaded in $outFile" } function Add-HASCertificate { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$siteName, [Parameter(Mandatory)] [string]$domain, [string]$contact = 'contact@mega.com' ) # Update SSL certificate # https://www.virtualtothecore.com/new-year-new-lets-encrypt-automation-goodbye-acmesharp-hello-posh-acme/ Write-Output "Generate certificate" Import-Module Posh-Acme -force Set-PaServer LE_PROD $pfxPass = "Hopex" New-PACertificate $domain -AcceptTOS -Contact $contact -pfxPass $pfxPass -Plugin WebSelfHost -PluginArgs @{} $cert = Get-PACertificate -MainDomain $domain Write-Output "Create IIS https binding" New-WebBinding -name $siteName -Protocol https -Port 443 -ErrorAction SilentlyContinue $cert | Set-IISCertificate -SiteName $siteName Remove-WebBinding -Name $siteName -Protocol http -ErrorAction SilentlyContinue ## Add certificate renewal script $T = New-JobTrigger -Weekly -At "3:00 AM" -DaysOfWeek Monday -RandomDelay 0:30:00 Register-ScheduledJob -Name "RenewCertificateWeekly" -Trigger $T -ErrorAction SilentlyContinue -ScriptBlock { Import-Module Posh-Acme Import-Module Posh-Acme.deploy Set-PAOrder $domain if ($cert = Submit-Renewal) { $cert | Set-IISCertificate -SiteName $siteName -RemoveOldCert } } $T = New-JobTrigger -AtStartup Register-ScheduledJob -Name "RenewCertificateOnStart" -Trigger $T -ErrorAction SilentlyContinue -ScriptBlock { Import-Module Posh-Acme Import-Module Posh-Acme.deploy $cert = submit-renewal $domain -force $cert | Set-IISCertificate -SiteName $siteName -RemoveOldCert } } function Install-HASInstanceManager { [CmdletBinding(DefaultParametersetName = "default")] param( [Parameter(Mandatory, HelpMessage = "HOPEX store token")] [String]$token, [Parameter()] [ValidateRange(5000, 60000)] [int]$port = 30100, [Parameter(Mandatory)] [string]$password, [Parameter(ParameterSetName="fromCmdLine")] [ValidatePattern("^([^v:]+)[v:]([0-9\.]+)$")] [String]$bundle, [Parameter()] [String]$installer = 'has.setup.exe', [Parameter()] [ValidateSet("Development", "Training", "Production")] [String]$mode = 'Production', [Parameter()] [ValidateRange(5000, 60000)] [int]$start, [Parameter(HelpMessage = "HOPEX store address (eg. https://store.mega.com)")] [String]$server = 'https://store.mega.com', [Parameter(ParameterSetName="fromCmdLine")] [String]$provisionFile, [Parameter(HelpMessage = "Max waiting time in seconds")] [int]$wait, [Parameter(ValueFromPipeline, ParameterSetName="fromPipeline")] [PSCustomObject] $provision ) Write-Output "Installing HAS with $installer..." if($provision) { $provisionFile = '.provision' $provision | Save-HASProvisionFile -outFile $provisionFile $bundle = $provision.bundle.bundle + ":" + $provision.bundle.version if(!$start) { $start = 5000 } } Write-Output " Preparing settings file..." $settings = [PSCustomObject]@{ AgentPort = $port ApiKey = $password HopexStoreAddress = $server HopexStoreToken = $token RunningMode = $mode Bundle = $bundle } if ($start) { $settings | Add-Member -NotePropertyName "InstancePort" -NotePropertyValue $start $settings | Add-Member -NotePropertyName "TemplateFile" -NotePropertyValue $provisionFile } $settings | ConvertTo-Json | Set-Content -Path settings.json -Force Try { Write-Output "Running setup..." Start-Process -FilePath $installer -ArgumentList "install settings.json" -Wait If (Test-Path ".\has.setup.log") { If (Select-String -Path ".\has.setup.log" -pattern "Installation completed successfully") { Write-Output "Installation completed successfully" } Else { Write-Output "Installation failed" Throw "Error installing HAS setup" } } Else { Write-Output "WARNING: installing HAS setup (installation log is missing)" } } Catch { Throw $_ } Finally { Remove-Item settings.json } if ($wait) { Start-Sleep -Seconds 10 Wait-ForHASReady -wait $wait -port $start } } function Wait-ForHASReady { [CmdletBinding()] param( [Parameter()] [ValidateRange(5000, 60000)] [int]$port = 5000, [Parameter(HelpMessage = "Max waiting time in seconds")] [int]$wait = 2700 ) Try { $HASStatusCode = "" $Timer = [Diagnostics.Stopwatch]::StartNew() Write-Output "Waiting for HAS to start for $($wait/60) minutes..." While (($HASStatusCode -ne "200")) { Try { $HASStatusCode = (Invoke-WebRequest -URI "$HASPublicAddress/admin/cluster/health" -UseBasicParsing -ErrorAction SilentlyContinue).StatusCode } Catch {} if ($Timer.Elapsed.TotalSeconds -ge $wait) { break } Start-Sleep -Seconds 10 } If ($Timer.Elapsed.TotalSeconds -ge $wait) { Throw "Error timeout during HAS start up ($($wait/60) min)" } Else { Write-Output "HAS successfully started" cscript.exe ChangePassword.vbs $context.password } } Catch { Throw $_ } Finally { $Timer.Reset() $Timer.Stop() } } function Copy-HASWebConfig { [CmdletBinding()] param( [Parameter()] [string]$iisFolder = 'C:\inetpub\wwwroot\has\' ) $webConfig = (Get-ChildItem -Recurse -Path 'C:\ProgramData\MEGA\Hopex Application Server\.binaries\' -Include web.config).fullname | Select -First 1 $sourceIISFolder = Split-Path $webConfig Write-Host "Copy $sourceIISFolder\..\iis to iis folder $iisFolder" copy-item "$sourceIISFolder\..\iis\*" $iisFolder -force } # ----------------------------------------------------------- # Provision file # ----------------------------------------------------------- function New-HASProvision { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $bundle, [Parameter(Mandatory)] [string] $publicAddress, [Parameter()] [string] $adminPassword, [Parameter()] [Switch] $noSsl ) $bundle = $bundle.replace('+', '.') $pattern = '([^v:]+)([v:])([0-9\.]+)' $match = [regex]::match($bundle, $pattern) return [PSCustomObject]@{ bundle = @{ bundle = $match.Groups[1].Value versionName = $bundle -replace $pattern, '$1 V$3' version = $match.Groups[3].Value } configuration = @{ publicAddress = $publicAddress adminPassword = $(if ($adminPassword) { $adminPassword } else { $null }) noSsl = $(if ($noSsl) { $true } else { $false }) } }; } function Add-HASProvisionModule { [CmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipeline)] [PSCustomObject] $inputProvision, [Parameter(Mandatory)] [string] $id, [Parameter()] [string] $version ) Process { $modules = $inputProvision.modules; if ($null -eq $modules) { $modules = @(); $inputProvision | Add-Member -NotePropertyName modules -NotePropertyValue $modules } $inputProvision.modules += [PSCustomObject]@{ id = $id version = $(if ($version) { $version } else { $null }) }; return [PSCustomObject]$inputProvision } } function Add-HASProvisionMegasiteEntry { [CmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipeline)] [PSCustomObject] $inputProvision, [Parameter(Mandatory)] [string] $section, [Parameter(Mandatory)] [string] $name, [Parameter(Mandatory)] [string] $value ) Process { try { $stage = $inputProvision.stages[0]; } catch { $stage = [PSCustomObject] @{ megaSite = [PSCustomObject]@{} }; $stages = @($stage) $inputProvision | Add-Member -NotePropertyName stages -NotePropertyValue $stages } $stage.megasite | Add-Member -NotePropertyName "[$section].$name" -NotePropertyValue $value return [PSCustomObject]$inputProvision } } function Save-HASProvisionFile { [CmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipeline)] [PSCustomObject] $inputProvision, [Parameter()] [string] $outFile = 'provision.json' ) Write-Output $inputProvision | ConvertTo-Json -Depth 10 -Compress | Set-Content -Path $outFile -Force } |