Files
windows-imaging-tools-builder/Build-Image.ps1
T

78 lines
5.0 KiB
PowerShell

[CmdletBinding(SupportsShouldProcess=$true)]
param([string]$ConfigPath,[switch]$SkipBootVerification,[Parameter(DontShow=$true)][switch]$InternalWorker,[Parameter(DontShow=$true)][string]$ResourceContextPath)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'scripts\Project.Common.ps1')
. (Join-Path $PSScriptRoot 'scripts\Build.Validation.ps1')
Assert-PowerShell51
$settings=Get-ProjectSettings
if(-not$ConfigPath){$ConfigPath=Join-Path $ProjectRoot 'local\image.ini'}
if(-not(Test-Path -LiteralPath $ConfigPath -PathType Leaf)){throw 'Generate a local image config with New-ImageConfig.ps1 first.'}
$priorWhatIf=$WhatIfPreference
try {
$WhatIfPreference=$false
if ($InternalWorker) { . (Join-Path $ProjectRoot 'scripts\Import-ImagingTools.ps1') -Settings $settings -ResourceContextPath $ResourceContextPath }
else { . (Join-Path $ProjectRoot 'scripts\Import-ImagingTools.ps1') -Settings $settings }
$config=Get-WindowsImageConfig -ConfigFilePath $ConfigPath
$inputs=Assert-ImageBuildInputs -Settings $settings -Config $config -CheckHost
$tools=Get-ImageServicingTools
}
finally{$WhatIfPreference=$priorWhatIf}
if(-not$PSCmdlet.ShouldProcess($config.image_path,'Build a Windows image using Hyper-V and Sysprep')){
[PSCustomObject]@{OutputPath=$config.image_path;DiskGiB=([long]$config.disk_size/1GB);Upstream=$settings.UpstreamRoot;HostChecks=$inputs.HostChecks;DismVersion=$tools.DismVersion;BcdbootVersion=$tools.BcdbootVersion}
return
}
Assert-Administrator
if (-not $InternalWorker) {
. (Join-Path $ProjectRoot 'scripts\Build.Cancellation.ps1')
Invoke-PveControlledBuild -ScriptPath $PSCommandPath -ConfigPath $ConfigPath -Settings $settings -Config $config -ServicingIsoPath $inputs.Software.ServicingIsoPath -SkipBootVerification:$SkipBootVerification
return
}
. (Join-Path $ProjectRoot 'scripts\Build.Resources.ps1')
$resources=Get-PveBuildResources -ContextPath $ResourceContextPath
if ($resources.OutputPath -ine [IO.Path]::GetFullPath($config.image_path) -or $resources.AssetsRoot -ine [IO.Path]::GetFullPath($settings.AssetsRoot)) { throw 'Worker configuration differs from its resource owner.' }
$runId=$resources.RunId
$logDirectory=$resources.LogDirectory
$state=[ordered]@{Phase='starting';StartedUtc=[DateTime]::UtcNow.ToString('o');ConfigPath=[IO.Path]::GetFullPath($ConfigPath);OutputPath=$config.image_path;ImageName=$config.image_name;ImageVersion=$inputs.ImageVersion;ServicingTools=$tools;LogDirectory=$logDirectory}
function Save-BuildState {
[IO.File]::WriteAllText((Join-Path $logDirectory 'status.json'),($state|ConvertTo-Json -Depth 7),[Text.UTF8Encoding]::new($false))
}
$transcriptStarted=$false
$priorPath=$env:Path
try{
Save-BuildState
Start-Transcript -Path (Join-Path $logDirectory 'build-transcript.txt')|Out-Null
$transcriptStarted=$true
& (Get-Module WinImageBuilder) {
param($Directory,$ToolPaths,$KeyMode)
$script:PveRunLogDirectory=$Directory
$script:PveServicingTools=$ToolPaths
if ($KeyMode) { $script:PveProductKeyMode=$KeyMode }
} $logDirectory $tools $inputs.Software.ProductKeyMode
$servicingIso=$null
$isoProperty=$inputs.Software.PSObject.Properties['ServicingIsoPath']
if($isoProperty){$servicingIso=$isoProperty.Value}
if(-not$servicingIso -and [IO.Path]::GetExtension($config.wim_file_path) -ieq '.iso'){$servicingIso=$config.wim_file_path}
if(-not$servicingIso){throw 'Provide a matching Windows installer ISO with New-ImageConfig.ps1 -ServicingIsoPath for isolated Windows PE servicing.'}
& (Get-Module WinImageBuilder) {param($IsoPath);$script:PveServicingIsoPath=$IsoPath} $servicingIso
$state.ServicingMode='isolated_windows_pe';Save-BuildState
$state.Phase='building';Save-BuildState
$env:Path=(Split-Path -Parent $tools.DismPath)+';'+(Split-Path -Parent $tools.BcdbootPath)+';'+$priorPath
New-WindowsOnlineImage -ConfigFilePath $ConfigPath
if(-not(Test-Path -LiteralPath $config.image_path -PathType Leaf)){throw 'The builder returned without publishing an image.'}
if(-not$SkipBootVerification){
$state.Phase='verifying_boot';Save-BuildState
$boot=& (Join-Path $ProjectRoot 'Verify-BuiltImage.ps1') -SourcePath $config.image_path -ConfigPath $ConfigPath -LogDirectory (Join-Path $logDirectory 'boot-verification') -ResourceContextPath $ResourceContextPath
$state.BootVerification=$boot.Phase
}else{$state.BootVerification='not_requested'}
$state.Phase='complete';$state.CompletedUtc=[DateTime]::UtcNow.ToString('o')
$state.SHA256=(Get-FileHash -LiteralPath $config.image_path -Algorithm SHA256).Hash
$state.OutputBytes=(Get-Item -LiteralPath $config.image_path).Length
Save-BuildState
$resources=Get-PveBuildResources -ContextPath $ResourceContextPath
$resources.Completed=$true
Save-PveBuildResources -ContextPath $ResourceContextPath -Context $resources
}catch{
$state.Phase='failed';$state.Error=$_.Exception.Message;Save-BuildState
throw ('Build failed. Logs: '+$logDirectory+'. '+$_.Exception.Message)
}finally{$env:Path=$priorPath;if($transcriptStarted){Stop-Transcript|Out-Null}}