Files

124 lines
9.3 KiB
PowerShell

param([Parameter(Mandatory=$true)]$Settings,[string]$ResourceContextPath)
Import-Module (Join-Path $Settings.UpstreamRoot 'WinImageBuilder.psm1') -Force
Import-Module (Join-Path $Settings.UpstreamRoot 'Config.psm1') -Force
& (Get-Module WinImageBuilder) {
param($ProjectRoot,$AssetsRoot,$ManifestPath,$ResourceContextPath)
$script:PveProjectRoot=$ProjectRoot;$script:PveAssetsRoot=$AssetsRoot;$script:PveQemuManifest=$ManifestPath
$script:PveDeferredServicing=$false
$script:PveServicingIsoPath=$null
$script:PveResourceContextPath=$ResourceContextPath
$script:PveProductKeyMode='Legacy'
. (Join-Path $ProjectRoot 'scripts\Build.Resources.ps1')
. (Join-Path $ProjectRoot 'scripts\CloudbaseInit.Resources.ps1')
if (-not (Get-Variable -Name PveOriginalDownloadCloudbaseInit -Scope Script -ErrorAction SilentlyContinue)) { $script:PveOriginalDownloadCloudbaseInit=${function:Download-CloudbaseInit} }
function script:Download-CloudbaseInit {
param([string]$resourcesDir,[string]$osArch,[switch]$BetaRelease,[string]$MsiPath,[string]$CloudbaseInitConfigPath,[string]$CloudbaseInitUnattendedConfigPath)
$cachePath=Get-PveCloudbaseInitCachePath -AssetsRoot $script:PveAssetsRoot -OsArch $osArch -BetaRelease:$BetaRelease
$templatePath=Get-PveCloudbaseInitCachePath -AssetsRoot $script:PveAssetsRoot
if (-not $MsiPath -or [IO.Path]::GetFullPath($MsiPath) -in @($cachePath,$templatePath)) {
$PSBoundParameters['MsiPath']=Execute-Retry {
Initialize-PveCloudbaseInitInstaller -AssetsRoot $script:PveAssetsRoot -OsArch $osArch -BetaRelease:$BetaRelease
}
}
& $script:PveOriginalDownloadCloudbaseInit @PSBoundParameters
}
. (Join-Path $ProjectRoot 'scripts\Unattend.Adapter.ps1')
if (-not (Get-Variable -Name PveOriginalGenerateUnattend -Scope Script -ErrorAction SilentlyContinue)) { $script:PveOriginalGenerateUnattend=${function:Generate-UnattendXml} }
function script:Generate-UnattendXml {
param([string]$inUnattendXmlPath,[string]$outUnattendXmlPath,$image,[string]$productKey,$administratorPassword)
$setupKey=Get-PveSetupProductKey -Image $image -RequestedProductKey $productKey -Mode $script:PveProductKeyMode
$automatic=($script:PveProductKeyMode -eq 'Kms' -or (-not $productKey -and -not [string]::IsNullOrWhiteSpace($setupKey)))
if ($setupKey) { $PSBoundParameters['productKey']=$setupKey }
else { $PSBoundParameters.Remove('productKey') | Out-Null }
& $script:PveOriginalGenerateUnattend @PSBoundParameters
Update-PveUnattendSettings -Path $outUnattendXmlPath -Image $image -AutomaticSetupKey:$automatic
if ($automatic) { Write-Log 'Public KMS client setup key supplied for the selected edition; build-time automatic activation disabled.' }
}
. (Join-Path $ProjectRoot 'scripts\Servicing.Adapter.ps1')
if (-not (Get-Variable -Name PveOriginalGetPath -Scope Script -ErrorAction SilentlyContinue)) { $script:PveOriginalGetPath = ${function:Get-PathWithoutExtension} }
function script:Get-PathWithoutExtension {
param([string]$Path,[int]$Depth=0)
if ([IO.Path]::GetExtension($Path).ToLowerInvariant() -in @('.qcow2','.vhdx','.vhd','.raw')) {
return Join-Path ([IO.Path]::GetDirectoryName($Path)) ([IO.Path]::GetFileNameWithoutExtension($Path))
}
& $script:PveOriginalGetPath -Path $Path -Depth $Depth
}
if (-not (Get-Variable -Name PveOriginalRunSysprep -Scope Script -ErrorAction SilentlyContinue)) {
$script:PveOriginalRunSysprep = ${function:Run-Sysprep}
}
if (-not (Get-Variable -Name PveOriginalCopyUnattendResources -Scope Script -ErrorAction SilentlyContinue)) { $script:PveOriginalCopyUnattendResources=${function:Copy-UnattendResources} }
function script:Copy-UnattendResources {
param([string]$resourcesDir,[string]$imageInstallationType,[bool]$InstallMaaSHooks,[string]$VMwareToolsPath)
& $script:PveOriginalCopyUnattendResources @PSBoundParameters
Copy-Item -LiteralPath (Join-Path $script:PveProjectRoot 'resources\Builder.Specialize.ps1') -Destination (Join-Path $resourcesDir 'Specialize.ps1') -Force
}
if (-not (Get-Variable -Name PveOriginalAddVirtioIso -Scope Script -ErrorAction SilentlyContinue)) { $script:PveOriginalAddVirtioIso=${function:Add-VirtIODriversFromISO} }
function script:Add-VirtIODriversFromISO {
param([string]$vhdDriveLetter,$image,[string]$isoPath)
if ($script:PveResourceContextPath) {
$directory=Join-Path $script:PveRunLogDirectory ('temporary-virtio-'+[guid]::NewGuid().ToString('N'))
Register-PveBuildDirectory -ContextPath $script:PveResourceContextPath -Path $directory
New-Item -ItemType Directory -Path $directory | Out-Null
$copy=Join-Path $directory 'virtio.iso'
Copy-Item -LiteralPath $isoPath -Destination $copy
try { & $script:PveOriginalAddVirtioIso -vhdDriveLetter $vhdDriveLetter -image $image -isoPath $copy }
finally {
if (Test-Path -LiteralPath $copy -PathType Leaf) { Assert-PveResourcePath -Path $copy -Root $directory -Descendant | Out-Null; Remove-Item -LiteralPath $copy -Force }
if ((Test-Path -LiteralPath $directory -PathType Container) -and -not @(Get-ChildItem -LiteralPath $directory -Force).Count) { Remove-Item -LiteralPath $directory }
}
} else { & $script:PveOriginalAddVirtioIso @PSBoundParameters }
}
function script:Run-Sysprep {
param([string]$Name,[string]$VhdPath,[uint64]$Memory,[int]$CpuCores,[string]$VMSwitch,[string]$Generation='1',[switch]$DisableSecureBoot)
if($script:PveDeferredServicing){
. (Join-Path $script:PveProjectRoot 'scripts\WindowsPE.Servicing.ps1')
Write-Log 'Starting isolated Windows PE EFI configuration and driver injection.'
Invoke-WindowsPeServicing -VhdPath $VhdPath -WindowsIsoPath $script:PveServicingIsoPath -LogDirectory (Join-Path $script:PveRunLogDirectory 'windows-pe')
}
if ($script:PveResourceContextPath) {
$Name='PveBuilder-Sysprep-'+[guid]::NewGuid().ToString('N')
$PSBoundParameters['Name']=$Name
Register-PveBuildVm -ContextPath $script:PveResourceContextPath -Name $Name -VhdPath $VhdPath
}
try { & $script:PveOriginalRunSysprep @PSBoundParameters }
catch {
$own=Get-VM -Name $Name -ErrorAction SilentlyContinue
if($own){$disks=@(Get-VMHardDiskDrive -VM $own);if($disks.Count -eq 1 -and $disks[0].Path -ieq $VhdPath -and $own.State -ne 'Off'){Stop-VM -VM $own -TurnOff -Force}}
throw
}
. (Join-Path $script:PveProjectRoot 'scripts\Build.Validation.ps1')
$verification=Get-OfflineBuildVerification -VhdPath $VhdPath -Directory (Join-Path $script:PveRunLogDirectory 'verification')
[IO.File]::WriteAllText((Join-Path $script:PveRunLogDirectory 'verified-guest.json'),($verification|ConvertTo-Json -Depth 6),[Text.UTF8Encoding]::new($false))
Write-Log 'Guest software, required services, and generalized Sysprep state verified.'
}
function script:Wait-ForVMShutdown {
param([string]$Name)
$deadline=[DateTime]::UtcNow.AddHours(4)
$lastMessages=@{}
if ($script:PveResourceContextPath) {
$owned=Get-VM -Name $Name -ErrorAction Stop
$ownedDisks=@(Get-VMHardDiskDrive -VM $owned -ErrorAction Stop)
if ($ownedDisks.Count -ne 1) { throw 'The build VM must have exactly one owned disk.' }
Register-PveBuildVm -ContextPath $script:PveResourceContextPath -Name $Name -VhdPath $ownedDisks[0].Path -Id ([string]$owned.Id)
}
while ((Get-VM -Name $Name).State -ne 'Off') {
if([DateTime]::UtcNow -gt $deadline){throw ('Build VM timed out; retained for diagnosis: '+$Name)}
$messages=$null
try { $messages=Get-KVPData -VMName $Name } catch { Write-Verbose 'VM runtime logs are not available yet.' }
if($messages){foreach($key in $messages.Keys){if($lastMessages[$key] -ne $messages[$key]){Write-Log ('{0}: {1}' -f $key,$messages[$key])};if($key -ieq 'ERROR'){throw ('Build guest reported an error; VM retained for diagnosis: '+$Name+'. '+$messages[$key])}};$lastMessages=$messages}
Start-Sleep -Seconds 3
}
}
function script:Convert-VirtualDisk {
param([Parameter(Mandatory=$true)][string]$vhdPath,[Parameter(Mandatory=$true)][string]$outPath,[Parameter(Mandatory=$true)][string]$format,[bool]$CompressQcow2)
if($format.ToLower() -eq 'qcow2' -and $CompressQcow2){
$result=& (Join-Path $script:PveProjectRoot 'src\Compress-Qcow2Image.ps1') -SourcePath $vhdPath -OutputPath $outPath -ToolManifestPath $script:PveQemuManifest -BackupDirectory (Join-Path $script:PveAssetsRoot 'archive\verified-builds') -ReplaceExisting -ResourceContextPath $script:PveResourceContextPath
Write-Log ('Verified compressed image: '+$result.OutputPath)
}else{
$manifest=Get-Content -Raw -Encoding UTF8 -LiteralPath $script:PveQemuManifest|ConvertFrom-Json
& $manifest.ExecutablePath convert -m 1 -O $format $vhdPath $outPath
if($LASTEXITCODE -ne 0){throw 'Disk conversion failed.'}
}
}
} $Settings.ProjectRoot $Settings.AssetsRoot $Settings.QemuManifestPath $ResourceContextPath