mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
7670ab886c
Includes Secure Boot support in the PE image so firmware variables can be inspected during imaging. Captures baseline, post-apply, and final boot evidence for firmware state, storage layout, boot files, and boot configuration to explain UEFI boot failures and highlight likely dbx blocks or boot entry issues.
210 lines
7.9 KiB
PowerShell
210 lines
7.9 KiB
PowerShell
param (
|
|
[string]$FFUDevelopmentPath = $PSScriptRoot,
|
|
[string]$adkPath = 'C:\Program Files (x86)\Windows Kits\10\',
|
|
[string]$WindowsArch = 'x64',
|
|
[bool]$CopyPEDrivers = $false,
|
|
[string]$CaptureISO = "$PSScriptRoot\WinPE_FFU_Capture_x64.iso",
|
|
[string]$DeployISO = "$PSScriptRoot\WinPE_FFU_Deploy_x64.iso",
|
|
[string]$LogFile = "$PSScriptRoot\Create-PEMedia.log",
|
|
[bool]$Capture,
|
|
[bool]$Deploy = $true
|
|
)
|
|
|
|
function WriteLog($LogText) {
|
|
Add-Content -path $LogFile -value "$((Get-Date).ToString()) $LogText" -Force -ErrorAction SilentlyContinue
|
|
Write-Verbose $LogText
|
|
}
|
|
|
|
function Invoke-Process {
|
|
[CmdletBinding(SupportsShouldProcess)]
|
|
param
|
|
(
|
|
[Parameter(Mandatory)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]$FilePath,
|
|
|
|
[Parameter()]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]$ArgumentList
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
try {
|
|
$stdOutTempFile = "$env:TEMP\$((New-Guid).Guid)"
|
|
$stdErrTempFile = "$env:TEMP\$((New-Guid).Guid)"
|
|
|
|
$startProcessParams = @{
|
|
FilePath = $FilePath
|
|
ArgumentList = $ArgumentList
|
|
RedirectStandardError = $stdErrTempFile
|
|
RedirectStandardOutput = $stdOutTempFile
|
|
Wait = $true;
|
|
PassThru = $true;
|
|
NoNewWindow = $true;
|
|
}
|
|
if ($PSCmdlet.ShouldProcess("Process [$($FilePath)]", "Run with args: [$($ArgumentList)]")) {
|
|
$cmd = Start-Process @startProcessParams
|
|
$cmdOutput = Get-Content -Path $stdOutTempFile -Raw
|
|
$cmdError = Get-Content -Path $stdErrTempFile -Raw
|
|
if ($cmd.ExitCode -ne 0) {
|
|
if ($cmdError) {
|
|
throw $cmdError.Trim()
|
|
}
|
|
if ($cmdOutput) {
|
|
throw $cmdOutput.Trim()
|
|
}
|
|
}
|
|
else {
|
|
if ([string]::IsNullOrEmpty($cmdOutput) -eq $false) {
|
|
WriteLog $cmdOutput
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
#$PSCmdlet.ThrowTerminatingError($_)
|
|
WriteLog $_
|
|
Write-Host "Script failed - $Logfile for more info"
|
|
throw $_
|
|
|
|
}
|
|
finally {
|
|
Remove-Item -Path $stdOutTempFile, $stdErrTempFile -Force -ErrorAction Ignore
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function New-PEMedia {
|
|
param (
|
|
[Parameter()]
|
|
[bool]$Capture,
|
|
[Parameter()]
|
|
[bool]$Deploy
|
|
)
|
|
#Need to use the Demployment and Imaging tools environment to create winPE media
|
|
$DandIEnv = "$adkPath`Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"
|
|
$WinPEFFUPath = "$FFUDevelopmentPath\WinPE"
|
|
|
|
If (Test-path -Path "$WinPEFFUPath") {
|
|
WriteLog "Removing old WinPE path at $WinPEFFUPath"
|
|
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force | out-null
|
|
}
|
|
|
|
WriteLog "Copying WinPE files to $WinPEFFUPath"
|
|
if($WindowsArch -eq 'x64') {
|
|
& cmd /c """$DandIEnv"" && copype amd64 $WinPEFFUPath" | Out-Null
|
|
}
|
|
elseif($WindowsArch -eq 'arm64') {
|
|
& cmd /c """$DandIEnv"" && copype arm64 $WinPEFFUPath" | Out-Null
|
|
}
|
|
#Invoke-Process cmd "/c ""$DandIEnv"" && copype amd64 $WinPEFFUPath"
|
|
WriteLog 'Files copied successfully'
|
|
|
|
WriteLog 'Mounting WinPE media to add WinPE optional components'
|
|
Mount-WindowsImage -ImagePath "$WinPEFFUPath\media\sources\boot.wim" -Index 1 -Path "$WinPEFFUPath\mount" | Out-Null
|
|
WriteLog 'Mounting complete'
|
|
|
|
$Packages = @(
|
|
"WinPE-WMI.cab",
|
|
"en-us\WinPE-WMI_en-us.cab",
|
|
"WinPE-NetFX.cab",
|
|
"en-us\WinPE-NetFX_en-us.cab",
|
|
"WinPE-Scripting.cab",
|
|
"en-us\WinPE-Scripting_en-us.cab",
|
|
"WinPE-PowerShell.cab",
|
|
"en-us\WinPE-PowerShell_en-us.cab",
|
|
"WinPE-SecureBootCmdlets.cab",
|
|
"WinPE-StorageWMI.cab",
|
|
"en-us\WinPE-StorageWMI_en-us.cab",
|
|
"WinPE-DismCmdlets.cab",
|
|
"en-us\WinPE-DismCmdlets_en-us.cab"
|
|
)
|
|
|
|
if($WindowsArch -eq 'x64'){
|
|
$PackagePathBase = "$adkPath`Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\"
|
|
}
|
|
elseif($WindowsArch -eq 'arm64'){
|
|
$PackagePathBase = "$adkPath`Assessment and Deployment Kit\Windows Preinstallation Environment\arm64\WinPE_OCs\"
|
|
}
|
|
|
|
|
|
foreach ($Package in $Packages) {
|
|
$PackagePath = Join-Path $PackagePathBase $Package
|
|
WriteLog "Adding Package $Package"
|
|
Add-WindowsPackage -Path "$WinPEFFUPath\mount" -PackagePath $PackagePath | Out-Null
|
|
WriteLog "Adding package complete"
|
|
}
|
|
If ($Capture) {
|
|
WriteLog "Copying $FFUDevelopmentPath\WinPECaptureFFUFiles\* to WinPE capture media"
|
|
Copy-Item -Path "$FFUDevelopmentPath\WinPECaptureFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force | out-null
|
|
WriteLog "Copy complete"
|
|
#Remove Bootfix.bin - for BIOS systems, shouldn't be needed, but doesn't hurt to remove for our purposes
|
|
#Remove-Item -Path "$WinPEFFUPath\media\boot\bootfix.bin" -Force | Out-null
|
|
# $WinPEISOName = 'WinPE_FFU_Capture.iso'
|
|
$WinPEISOFile = $CaptureISO
|
|
# $Capture = $false
|
|
}
|
|
If ($Deploy) {
|
|
WriteLog "Copying $FFUDevelopmentPath\WinPEDeployFFUFiles\* to WinPE deploy media"
|
|
Copy-Item -Path "$FFUDevelopmentPath\WinPEDeployFFUFiles\*" -Destination "$WinPEFFUPath\mount" -Recurse -Force | Out-Null
|
|
WriteLog 'Copy complete'
|
|
#If $CopyPEDrivers = $true, add drivers to WinPE media using dism
|
|
if ($CopyPEDrivers) {
|
|
WriteLog "Adding drivers to WinPE media"
|
|
try {
|
|
Add-WindowsDriver -Path "$WinPEFFUPath\Mount" -Driver "$FFUDevelopmentPath\PEDrivers" -Recurse -ErrorAction SilentlyContinue | Out-null
|
|
}
|
|
catch {
|
|
WriteLog 'Some drivers failed to be added to the FFU. This can be expected. Continuing.'
|
|
}
|
|
WriteLog "Adding drivers complete"
|
|
}
|
|
# $WinPEISOName = 'WinPE_FFU_Deploy.iso'
|
|
$WinPEISOFile = $DeployISO
|
|
|
|
# $Deploy = $false
|
|
}
|
|
WriteLog 'Dismounting WinPE media'
|
|
Dismount-WindowsImage -Path "$WinPEFFUPath\mount" -Save | Out-Null
|
|
WriteLog 'Dismount complete'
|
|
#Make ISO
|
|
if ($WindowsArch -eq 'x64') {
|
|
$OSCDIMGPath = "$adkPath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg"
|
|
}
|
|
elseif ($WindowsArch -eq 'arm64') {
|
|
$OSCDIMGPath = "$adkPath`Assessment and Deployment Kit\Deployment Tools\arm64\Oscdimg"
|
|
}
|
|
$OSCDIMG = "$OSCDIMGPath\oscdimg.exe"
|
|
WriteLog "Creating WinPE ISO at $WinPEISOFile"
|
|
# & "$OSCDIMG" -m -o -u2 -udfver102 -bootdata:2`#p0,e,b$OSCDIMGPath\etfsboot.com`#pEF,e,b$OSCDIMGPath\Efisys_noprompt.bin $WinPEFFUPath\media $FFUDevelopmentPath\$WinPEISOName | Out-null
|
|
if($WindowsArch -eq 'x64'){
|
|
if($Capture){
|
|
$OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:2`#p0,e,b`"$OSCDIMGPath\etfsboot.com`"`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`""
|
|
}
|
|
if($Deploy){
|
|
$OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:2`#p0,e,b`"$OSCDIMGPath\etfsboot.com`"`#pEF,e,b`"$OSCDIMGPath\Efisys.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`""
|
|
}
|
|
}
|
|
elseif($WindowsArch -eq 'arm64'){
|
|
if($Capture){
|
|
$OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:1`#pEF,e,b`"$OSCDIMGPath\Efisys_noprompt.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`""
|
|
}
|
|
if($Deploy){
|
|
$OSCDIMGArgs = "-m -o -u2 -udfver102 -bootdata:1`#pEF,e,b`"$OSCDIMGPath\Efisys.bin`" `"$WinPEFFUPath\media`" `"$WinPEISOFile`""
|
|
}
|
|
|
|
}
|
|
Invoke-Process $OSCDIMG $OSCDIMGArgs
|
|
WriteLog "ISO created successfully"
|
|
WriteLog "Cleaning up $WinPEFFUPath"
|
|
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force
|
|
WriteLog 'Cleanup complete'
|
|
}
|
|
if($Capture){
|
|
New-PEMedia -Capture $Capture
|
|
}
|
|
if($Deploy){
|
|
New-PEMedia -Deploy $Deploy
|
|
} |