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-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 }