mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
c135ad0fba
By optimizing and mounting the VHDX directly on the host for image capture, the build process no longer needs to boot the VM into WinPE, create SMB network shares, generate temporary local accounts, or rely on complex Hyper-V switch IP configurations. This streamlines the workflow and eliminates multiple networking and permission-related points of failure. This change also removes the need to generate and attach WinPE capture media. All related parameters (`ShareName`, `Username`, `VMHostIPAddress`, `CreateCaptureMedia`, `CleanupCaptureISO`), UI controls, capture scripts, and documentation references have been removed or updated to reflect the simplified architecture.
170 lines
6.4 KiB
PowerShell
170 lines
6.4 KiB
PowerShell
param (
|
|
[string]$FFUDevelopmentPath = $PSScriptRoot,
|
|
[string]$adkPath = 'C:\Program Files (x86)\Windows Kits\10\',
|
|
[string]$WindowsArch = 'x64',
|
|
[bool]$CopyPEDrivers = $false,
|
|
[string]$DeployISO = "$PSScriptRoot\WinPE_FFU_Deploy_x64.iso",
|
|
[string]$LogFile = "$PSScriptRoot\Create-PEMedia.log"
|
|
)
|
|
|
|
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 ()
|
|
#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-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"
|
|
}
|
|
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"
|
|
}
|
|
$WinPEISOFile = $DeployISO
|
|
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'){
|
|
$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'){
|
|
$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'
|
|
}
|
|
New-PEMedia |