61 lines
4.1 KiB
PowerShell
61 lines
4.1 KiB
PowerShell
function script:Invoke-PveServicingTool {
|
|
param([string]$Executable,[string[]]$Arguments,[string]$Stage)
|
|
$output=@()
|
|
$priorErrorAction=$ErrorActionPreference
|
|
try {
|
|
$ErrorActionPreference='Continue'
|
|
$output=@(& $Executable @Arguments 2>&1 | ForEach-Object { $_.ToString() })
|
|
$exitCode=$LASTEXITCODE
|
|
} finally { $ErrorActionPreference=$priorErrorAction }
|
|
$entry=[ordered]@{Stage=$Stage;Executable=$Executable;Version=(Get-Item -LiteralPath $Executable).VersionInfo.FileVersion;Arguments=$Arguments;ExitCode=$exitCode;Output=$output;CheckedUtc=[DateTime]::UtcNow.ToString('o')}
|
|
$filename=$Stage+'-'+[guid]::NewGuid().ToString('N').Substring(0,8)+'.json'
|
|
[IO.File]::WriteAllText((Join-Path $script:PveRunLogDirectory $filename),($entry|ConvertTo-Json -Depth 5),[Text.UTF8Encoding]::new($false))
|
|
foreach($line in $output){Write-Log $line}
|
|
if($exitCode -ne 0 -and $exitCode -ne 3010){
|
|
$message=("$Stage failed (exit $exitCode). Logs: "+$script:PveRunLogDirectory)
|
|
if(($output -join ' ') -match 'c0000035'){$message+=' BCD hive collision: the host BCD must not be unloaded or modified; a compatible servicing environment is required.'}
|
|
throw $message
|
|
}
|
|
}
|
|
function script:Create-BCDBootConfig {
|
|
param([string]$systemDrive,[string]$windowsDrive,[string]$diskLayout,$image)
|
|
if($diskLayout -ne 'UEFI'){throw 'Only UEFI is supported by this project.'}
|
|
$systemLetter=$systemDrive.TrimEnd(':','\')
|
|
$windowsLetter=$windowsDrive.TrimEnd(':','\')
|
|
$efi=Get-Partition -DriveLetter $systemLetter
|
|
$windows=Get-Partition -DriveLetter $windowsLetter
|
|
$targetDisk=$efi|Get-Disk
|
|
if($efi.DiskNumber -ne $windows.DiskNumber -or $targetDisk.IsBoot -or $targetDisk.IsSystem){throw 'Refusing BCDBoot against a host system disk or mismatched partitions.'}
|
|
if([guid]$efi.GptType -ne [guid]'c12a7328-f81f-11d2-ba4b-00a0c93ec93b'){throw 'The selected system partition is not an EFI system partition.'}
|
|
if($script:PveServicingIsoPath){
|
|
$script:PveDeferredServicing=$true
|
|
$script:PveServicingWindowsDrive=$windowsDrive.TrimEnd('\')
|
|
$resources=$script:PveServicingWindowsDrive+'\UnattendResources'
|
|
New-Item -ItemType Directory -Path (Join-Path $resources 'PveDrivers') -Force|Out-Null
|
|
[IO.File]::WriteAllText((Join-Path $resources 'pve-servicing-marker.txt'),'PVE builder: service only this newly created image disk.')
|
|
[IO.File]::WriteAllText((Join-Path $resources 'pve-efi-partition.txt'),[string]$efi.PartitionNumber,[Text.Encoding]::ASCII)
|
|
Write-Log 'EFI boot configuration deferred to the isolated Windows PE servicing VM.'
|
|
return
|
|
}
|
|
$tool=$script:PveServicingTools.BcdbootPath
|
|
$help=(& $tool /? 2>&1|Out-String)
|
|
$arguments=@(($windowsDrive.TrimEnd('\')+'\Windows'),'/s',$systemDrive,'/f','UEFI','/v')
|
|
# Current Microsoft tools support offline servicing without firmware sync.
|
|
if($help -match '/offline'){$arguments+='/offline'}
|
|
Invoke-PveServicingTool -Executable $tool -Arguments $arguments -Stage 'bcdboot'
|
|
if(-not(Test-Path -LiteralPath ($systemDrive.TrimEnd('\')+'\EFI\Microsoft\Boot\BCD'))){throw 'BCDBoot did not create the image EFI BCD store.'}
|
|
}
|
|
function script:Add-DriversToImage {
|
|
param([string]$winImagePath,[string]$driversPath)
|
|
if($script:PveDeferredServicing){
|
|
if($winImagePath.TrimEnd('\') -ine $script:PveServicingWindowsDrive){throw 'Driver staging target differs from the build Windows partition.'}
|
|
$destination=$winImagePath.TrimEnd('\')+'\UnattendResources\PveDrivers\'+[guid]::NewGuid().ToString('N')
|
|
Copy-Item -LiteralPath $driversPath -Destination $destination -Recurse
|
|
Write-Log ('Staged drivers for Windows PE servicing: '+$driversPath)
|
|
return
|
|
}
|
|
$tool=$script:PveServicingTools.DismPath
|
|
$log=Join-Path $script:PveRunLogDirectory ('dism-'+[guid]::NewGuid().ToString('N').Substring(0,8)+'.log')
|
|
Invoke-PveServicingTool -Executable $tool -Arguments @(('/image:'+$winImagePath),'/Add-Driver',('/driver:'+$driversPath),'/recurse',('/LogPath:'+$log)) -Stage 'dism-add-driver'
|
|
}
|