Files

78 lines
4.8 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
function script:Get-PveCloudbaseInitPackage {
param([ValidateSet('AMD64','x64','i386','x86')][string]$OsArch='AMD64',[switch]$BetaRelease)
$architecture='x64'
if ($OsArch -in @('i386','x86')) { $architecture='x86' }
$suffix='_Stable'
if ($BetaRelease) { $suffix='' }
$name='CloudbaseInitSetup'+$suffix+'_'+$architecture+'.msi'
[PSCustomObject]@{Name=$name;Architecture=$architecture;Url=('https://www.cloudbase.it/downloads/'+$name)}
}
function script:Get-PveCloudbaseInitCachePath {
param([Parameter(Mandatory=$true)][string]$AssetsRoot,[string]$OsArch='AMD64',[switch]$BetaRelease)
$package=Get-PveCloudbaseInitPackage -OsArch $OsArch -BetaRelease:$BetaRelease
[IO.Path]::GetFullPath((Join-Path $AssetsRoot ('assets\'+$package.Name)))
}
function script:Assert-PveCloudbaseInitInstaller {
param([Parameter(Mandatory=$true)][string]$Path,[string]$OsArch='AMD64')
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { throw ('Cloudbase-Init installer is missing: '+$Path) }
$installer=$null;$database=$null;$view=$null;$record=$null;$summary=$null
try {
$installer=New-Object -ComObject WindowsInstaller.Installer
# Open the MSI read-only; this does not install software on the build host.
$database=$installer.GetType().InvokeMember('OpenDatabase','InvokeMethod',$null,$installer,@([IO.Path]::GetFullPath($Path),0))
$view=$database.GetType().InvokeMember('OpenView','InvokeMethod',$null,$database,@('SELECT `Value` FROM `Property` WHERE `Property` = ''ProductName'''))
$view.GetType().InvokeMember('Execute','InvokeMethod',$null,$view,$null) | Out-Null
$record=$view.GetType().InvokeMember('Fetch','InvokeMethod',$null,$view,$null)
if (-not $record) { throw 'MSI ProductName is missing.' }
$product=$record.GetType().InvokeMember('StringData','GetProperty',$null,$record,@(1))
if ($product -notmatch '^Cloudbase-Init(?: \d[\w.+-]*)?$') { throw ('Unexpected MSI product: '+$product) }
$summary=$database.GetType().InvokeMember('SummaryInformation','GetProperty',$null,$database,@(0))
$platform=($summary.GetType().InvokeMember('Property','GetProperty',$null,$summary,@(7)) -split ';')[0]
$expected='x64'
if ((Get-PveCloudbaseInitPackage -OsArch $OsArch).Architecture -eq 'x86') { $expected='Intel' }
if ($platform -ine $expected) { throw ('Incorrect MSI architecture: '+$platform+'; expected '+$expected) }
} catch { throw ('Cloudbase-Init installer is not a valid matching MSI: '+$Path+'. '+$_.Exception.Message) }
finally {
foreach ($comObject in @($summary,$record,$view,$database,$installer)) {
if ($null -ne $comObject) { [Runtime.InteropServices.Marshal]::FinalReleaseComObject($comObject) | Out-Null }
}
}
}
function script:Invoke-PveCloudbaseInitDownload {
param([string]$Uri,[string]$Destination)
$previousProtocol=[Net.ServicePointManager]::SecurityProtocol
try {
[Net.ServicePointManager]::SecurityProtocol=$previousProtocol -bor [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $Uri -OutFile $Destination -UseBasicParsing -TimeoutSec 300 -ErrorAction Stop
} finally { [Net.ServicePointManager]::SecurityProtocol=$previousProtocol }
}
function script:Initialize-PveCloudbaseInitInstaller {
param([Parameter(Mandatory=$true)][string]$AssetsRoot,[string]$OsArch='AMD64',[switch]$BetaRelease)
$package=Get-PveCloudbaseInitPackage -OsArch $OsArch -BetaRelease:$BetaRelease
$destination=Get-PveCloudbaseInitCachePath -AssetsRoot $AssetsRoot -OsArch $OsArch -BetaRelease:$BetaRelease
if (Test-Path -LiteralPath $destination -PathType Leaf) {
try {
Assert-PveCloudbaseInitInstaller -Path $destination -OsArch $OsArch
Write-Host ('复用 Cloudbase-Init 安装包:'+$destination)
return $destination
} catch { Write-Host ('Cloudbase-Init 缓存无效,重新下载:'+$destination) -ForegroundColor Yellow }
}
$directory=Split-Path -Parent $destination
New-Item -ItemType Directory -Path $directory -Force | Out-Null
$temporary=Join-Path $directory ($package.Name+'.'+[guid]::NewGuid().ToString('N')+'.partial.msi')
try {
Write-Host ('下载 Cloudbase-Init:'+$package.Url)
Invoke-PveCloudbaseInitDownload -Uri $package.Url -Destination $temporary
Assert-PveCloudbaseInitInstaller -Path $temporary -OsArch $OsArch
if (Test-Path -LiteralPath $destination -PathType Leaf) { [IO.File]::Replace($temporary,$destination,[System.Management.Automation.Language.NullString]::Value) }
else { [IO.File]::Move($temporary,$destination) }
return $destination
} finally {
if (Test-Path -LiteralPath $temporary -PathType Leaf) { Remove-Item -LiteralPath $temporary -Force }
}
}