78 lines
4.8 KiB
PowerShell
78 lines
4.8 KiB
PowerShell
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 }
|
||
}
|
||
}
|