8000 Add initial support for reusing drivers as PE drivers by JonasKloseBW · Pull Request #115 · rbalsleyMSFT/FFU · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add initial support for reusing drivers as PE drivers #115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 216 additions & 35 deletions FFUDevelopment/BuildFFUVM.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ param(
})]
[bool]$CopyDrivers,
[bool]$CopyPEDrivers,
[bool]$UseDriversAsPEDrivers,
[bool]$RemoveFFU,
[bool]$UpdateLatestCU,
[bool]$UpdatePreviewCU,
Expand Down Expand Up @@ -361,7 +362,7 @@ param(
[Parameter(Mandatory = $false)]
[string]$ExportConfigFile
)
$version = '2412.1'
$version = '2412.3'

# If a config file is specified and it exists, load it
if ($ConfigFile -and (Test-Path -Path $ConfigFile)) {
Expand Down Expand Up @@ -418,6 +419,26 @@ class VhdxCacheItem {
[VhdxCacheUpdateItem[]]$IncludedUpdates = @()
}

#Support for ini reading
$definition = @'
[DllImport("kernel32.dll")]
public static extern uint GetPrivateProfileString(
string lpAppName,
string lpKeyName,
string lpDefault,
System.Text.StringBuilder lpReturnedString,
uint nSize,
string lpFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern uint GetPrivateProfileSection(
string lpAppName,
byte[] lpReturnedString,
uint nSize,
string lpFileName);
'@
Add-Type -MemberDefinition $definition -Namespace Win32 -Name Kernel32 -PassThru

#Check if Hyper-V feature is installed (requires only checks the module)
$osInfo = Get-WmiObject -Class Win32_OperatingSystem
$isServer = $osInfo.Caption -match 'server'
Expand Down Expand Up @@ -557,7 +578,7 @@ function Invoke-Process {

[Parameter()]
[ValidateNotNullOrEmpty()]
[string]$ArgumentList,
[string[]]$ArgumentList,

[Parameter()]
[ValidateNotNullOrEmpty()]
Expand Down Expand Up @@ -1003,7 +1024,9 @@ function Get-HPDrivers {
$Arch = $WindowsArch -replace "^x", ""

# Construct the URL to download the driver XML cab for the model
$ModelRelease = $SystemID + "_$Arch" + "_$WindowsRelease" + ".0.$WindowsVersion"
# The HPcloud reference site is case sensitve so we must convert the Windowsversion to lower 'h' first
$WindowsVersionHP = $WindowsVersion -replace 'H', 'h'
$ModelRelease = $SystemID + "_$Arch" + "_$WindowsRelease" + ".0.$WindowsVersionHP"
$DriverCabUrl = "https://hpia.hpcloud.hp.com/ref/$SystemID/$ModelRelease.cab"
$DriverCabFile = "$DriversFolder\$ModelRelease.cab"
$DriverXmlFile = "$DriversFolder\$ModelRelease.xml"
Expand Down Expand Up @@ -2974,6 +2997,103 @@ Function Set-CaptureFFU {
}
}

function Get-PrivateProfileString {
param (
[Parameter()]
[string]$FileName,
[Parameter()]
[string]$SectionName,
[Parameter()]
[string]$KeyName
)
$sbuilder = [System.Text.StringBuilder]::new(1024)
[void][Win32.Kernel32]::GetPrivateProfileString($SectionName, $KeyName, "", $sbuilder, $sbuilder.Capacity, $FileName)

return $sbuilder.ToString()
}

function Get-PrivateProfileSection {
param (
[Parameter()]
[string]$FileName,
[Parameter()]
[string]$SectionName
)
$buffer = [byte[]]::new(16384)
[void][Win32.Kernel32]::GetPrivateProfileSection($SectionName, $buffer, $buffer.Length, $FileName)
$keyValues = [System.Text.Encoding]::Unicode.GetString($buffer).TrimEnd("`0").Split("`0")
$hashTable = @{}

foreach ($keyValue in $keyValues) {
if (![string]::IsNullOrEmpty($keyValue)) {
$parts = $keyValue -split "="
$hashTable[$parts[0]] = $parts[1]
}
}

return $hashTable
}

function Copy-Drivers {
param (
[Parameter()]
[string]$Path,
[Parameter()]
[string]$Output
)
#Find more information about device classes here:
#https://learn.microsoft.com/en-us/windows-hardware/drivers/install/system-defined-device-setup-classes-available-to-vendors
#For now, included are system devices, scsi and raid controllers, keyboards, mice and HID devices for touch support
$filterGUIDs = @("{4D36E97D-E325-11CE-BFC1-08002BE10318}", "{4D36E97B-E325-11CE-BFC1-08002BE10318}", "{4d36e96b-e325-11ce-bfc1-08002be10318}", "{d36e96f-e325-11ce-bfc1-08002be10318}", "{745a17a0-74d3-11d0-b6fe-00a0c90f57da}")
$exclusionList = "wdmaudio.inf|Sound|Machine Learning|Camera|Firmware"
$pathLength = $Path.Length
$infFiles = Get-ChildItem -Path $Path -Recurse -Filter "*.inf"

for ($i = 0; $i -lt $infFiles.Count; $i++) {
$infFullName = $infFiles[$i].FullName
$infPath = Split-Path -Path $infFullName
$childPath = $infPath.Substring($pathLength)
$targetPath = Join-Path -Path $Output -ChildPath $childPath

if ((Get-PrivateProfileString -FileName $infFullName -SectionName "version" -KeyName "ClassGUID") -in $filterGUIDs) {
#Avoid drivers that reference keywords from the exclusion list to keep the total size small
if (((Get-Content -Path $infFullName) -match $exclusionList).Length -eq 0) {
$providerName = (Get-PrivateProfileString -FileName $infFullName -SectionName "Version" -KeyName "Provider").Trim("%")

WriteLog "Copying PE drivers for $providerName"
WriteLog "Driver inf is: $infFullName"
[void](New-Item -Path $targetPath -ItemType Directory -Force)
Copy-Item -Path $infFullName -Destination $targetPath -Force
$CatalogFileName = Get-PrivateProfileString -FileName $infFullName -SectionName "version" -KeyName "Catalogfile"
Copy-Item -Path "$infPath\$CatalogFileName" -Destination $targetPath -Force

$sourceDiskFiles = Get-PrivateProfileSection -FileName $infFullName -SectionName "SourceDisksFiles"
foreach ($sourceDiskFile in $sourceDiskFiles.Keys) {
if (!$sourceDiskFiles[$sourceDiskFile].Contains(",")) {
Copy-Item -Path "$infPath\$sourceDiskFile" -Destination $targetPath -Force
} else {
$subdir = ($sourceDiskFiles[$sourceDiskFile] -split ",")[1]
[void](New-Item -Path "$targetPath\$subdir" -ItemType Directory -Force)
Copy-Item -Path "$infPath\$subdir\$sourceDiskFile" -Destination "$targetPath\$subdir" -Force
}
}

#Arch specific files override the files specified in the universal section
$sourceDiskFiles = Get-PrivateProfileSection -FileName $infFullName -SectionName "SourceDisksFiles.$WindowsArch"
foreach ($sourceDiskFile in $sourceDiskFiles.Keys) {
if (!$sourceDiskFiles[$sourceDiskFile].Contains(",")) {
Copy-Item -Path "$infPath\$sourceDiskFile" -Destination $targetPath -Force
} else {
$subdir = ($sourceDiskFiles[$sourceDiskFile] -split ",")[1]
[void](New-Item -Path "$targetPath\$subdir" -ItemType Directory -Force)
Copy-Item -Path "$infPath\$subdir\$sourceDiskFile" -Destination "$targetPath\$subdir" -Force
}
}
}
}
}
}

function New-PEMedia {
param (
[Parameter()]
Expand Down Expand Up @@ -3051,7 +3171,18 @@ function New-PEMedia {
if ($CopyPEDrivers) {
WriteLog "Adding drivers to WinPE media"
try {
Add-WindowsDriver -Path "$WinPEFFUPath\Mount" -Driver "$FFUDevelopmentPath\$PEDriversFolder" -Recurse -ErrorAction SilentlyContinue | Out-null
Add-WindowsDriver -Path "$WinPEFFUPath\Mount" -Driver "$PEDriversFolder" -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"
} elseif ($UseDriversAsPEDrivers) {
WriteLog "Copying drivers required for WinPE media"
Copy-Drivers -Path $DriversFolder -Output $PEDriversFolder
WriteLog "Adding drivers to WinPE media"
try {
Add-WindowsDriver -Path "$WinPEFFUPath\Mount" -Driver $PEDriversFolder -Recurse -ErrorAction SilentlyContinue | Out-null
}
catch {
WriteLog 'Some drivers failed to be added to the FFU. This can be expected. Continuing.'
Expand Down Expand Up @@ -3124,14 +3255,57 @@ function Optimize-FFUCaptureDrive {
throw $_
}
}

function Get-ShortenedWindowsSKU {
param (
[string]$WindowsSKU
)
$shortenedWindowsSKU = switch ($WindowsSKU) {
'Core' { 'Home' }
'CoreN' { 'Home_N' }
'CoreSingleLanguage' { 'Home_SL' }
'Education' { 'Edu' }
'EducationN' { 'Edu_N' }
'Professional' { 'Pro' }
'ProfessionalN' { 'Pro_N' }
'ProfessionalEducation' { 'Pro_Edu' }
'ProfessionalEducationN' { 'Pro_Edu_N' }
'ProfessionalWorkstation' { 'Pro_WKS' }
'ProfessionalWorkstationN' { 'Pro_WKS_N' }
'Enterprise' { 'Ent' }
'EnterpriseN' { 'Ent_N' }
'ServerStandard' { 'Srv_Std' }
'ServerDatacenter' { 'Srv_Dtc' }
'Home' { 'Home' }
'Home N' { 'Home_N' }
'Home Single Language' { 'Home_SL' }
'Education' { 'Edu' }
'Education N' { 'Edu_N' }
'Professional' { 'Pro' }
'Pro N' { 'Pro_N' }
'Pro Education' { 'Pro_Edu' }
'Pro Education N' { 'Pro_Edu_N' }
'Pro for Workstations' { 'Pro_WKS' }
'Pro N for Workstations' { 'Pro_WKS_N' }
'Enterprise' { 'Ent' }
'Enterprise N' { 'Ent_N' }
'Standard' { 'Srv_Std' }
'Standard (Desktop Experience)' { 'Srv_Std_DE' }
'Datacenter' { 'Srv_Dtc' }
'Datacenter (Desktop Experience)' { 'Srv_Dtc_DE' }
}
return $shortenedWindowsSKU

}
function New-FFUFileName {

$BuildDate = Get-Date -uformat %b%Y
# Replace '{WindowsRelease}' with the Windows release (e.g., 10, 11, 2016, 2019, 2022, 2025)
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{WindowsRelease}', $WindowsRelease
# Replace '{WindowsVersion}' with the Windows version (e.g., 1607, 1809, 21h2, 22h2, 23h2, 24h2, etc)
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{WindowsVersion}', $WindowsVersion
# Replace '{SKU}' with the SKU of the Windows image (e.g., Pro, Enterprise, etc.)
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{SKU}', $SKU
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{SKU}', $shortenedWindowsSKU
# Replace '{BuildDate}' with the current month and year (e.g., Jan2023)
$CustomFFUNameTemplate = $CustomFFUNameTemplate -replace '{BuildDate}', $BuildDate
# Replace '{yyyy}' with the current year in 4-digit format (e.g., 2023)
Expand Down Expand Up @@ -3197,42 +3371,44 @@ function New-FFU {
}
}
elseif (-not $InstallApps -and (-not $AllowVHDXCaching)) {
#Get Windows Version Information from the VHDX
$winverinfo = Get-WindowsVersionInfo
WriteLog 'Creating FFU File Name'
if ($CustomFFUNameTemplate) {
$FFUFileName = New-FFUFileName
}
else{
#Get Windows Version Information from the VHDX
$winverinfo = Get-WindowsVersionInfo
$FFUFileName = "$($winverinfo.Name)`_$($winverinfo.DisplayVersion)`_$($winverinfo.SKU)`_$($winverinfo.BuildDate).ffu"
$FFUFileName = "$($winverinfo.Name)`_$($winverinfo.DisplayVersion)`_$($shortenedWindowsSKU)`_$($winverinfo.BuildDate).ffu"
}
WriteLog "FFU file name: $FFUFileName"
$FFUFile = "$FFUCaptureLocation\$FFUFileName"
#Capture the FFU
Invoke-Process cmd "/c ""$DandIEnv"" && dism /Capture-FFU /ImageFile:$FFUFile /CaptureDrive:\\.\PhysicalDrive$($vhdxDisk.DiskNumber) /Name:$($winverinfo.Name)$($winverinfo.DisplayVersion)$($winverinfo.SKU) /Compress:Default" | Out-Null
# Invoke-Process cmd "/c dism /Capture-FFU /ImageFile:$FFUFile /CaptureDrive:\\.\PhysicalDrive$($vhdxDisk.DiskNumber) /Name:$($winverinfo.Name)$($winverinfo.DisplayVersion)$($winverinfo.SKU) /Compress:Default" | Out-Null
WriteLog 'Capturing FFU'
Invoke-Process cmd "/c ""$DandIEnv"" && dism /Capture-FFU /ImageFile:$FFUFile /CaptureDrive:\\.\PhysicalDrive$($vhdxDisk.DiskNumber) /Name:$($winverinfo.Name)$($winverinfo.DisplayVersion)$($shortenedWindowsSKU) /Compress:Default" | Out-Null
WriteLog 'FFU Capture complete'
Dismount-ScratchVhdx -VhdxPath $VHDXPath
}
elseif (-not $InstallApps -and $AllowVHDXCaching) {
# Make $FFUFileName based on values in the config.json file
WriteLog 'Creating FFU File Name'
if ($CustomFFUNameTemplate) {
$FFUFileName 9E7A = New-FFUFileName
} else {
}
else {
$BuildDate = Get-Date -UFormat %b%Y
# Get Windows Information to make the FFU file name from the cachedVHDXInfo file
if ($installationType -eq 'Client') {
$FFUFileName = "Win$($cachedVHDXInfo.WindowsRelease)`_$($cachedVHDXInfo.WindowsVersion)`_$($cachedVHDXInfo.WindowsSKU)`_$BuildDate.ffu"
} else {
$FFUFileName = "Server$($cachedVHDXInfo.WindowsRelease)`_$($cachedVHDXInfo.WindowsVersion)`_$($cachedVHDXInfo.WindowsSKU)`_$BuildDate.ffu"
$FFUFileName = "Win$($cachedVHDXInfo.WindowsRelease)`_$($cachedVHDXInfo.WindowsVersion)`_$($shortenedWindowsSKU)`_$BuildDate.ffu"
}
else {
$FFUFileName = "Server$($cachedVHDXInfo.WindowsRelease)`_$($cachedVHDXInfo.WindowsVersion)`_$($shortenedWindowsSKU)`_$BuildDate.ffu"
}
}
WriteLog "FFU file name: $FFUFileName"
$FFUFile = "$FFUCaptureLocation\$FFUFileName"
#Dismount the VHDX

#Capture the FFU
Invoke-Process cmd "/c ""$DandIEnv"" && dism /Capture-FFU /ImageFile:$FFUFile /CaptureDrive:\\.\PhysicalDrive$($vhdxDisk.DiskNumber) /Name:$($cachedVHDXInfo.WindowsRelease)$($cachedVHDXInfo.WindowsVersion)$($cachedVHDXInfo.WindowsSKU) /Compress:Default" | Out-Null
# Invoke-Process cmd "/c dism /Capture-FFU /ImageFile:$FFUFile /CaptureDrive:\\.\PhysicalDrive$($vhdxDisk.DiskNumber) /Name:$($winverinfo.Name)$($winverinfo.DisplayVersion)$($winverinfo.SKU) /Compress:Default" | Out-Null
WriteLog 'Capturing FFU'
Invoke-Process cmd "/c ""$DandIEnv"" && dism /Capture-FFU /ImageFile:$FFUFile /CaptureDrive:\\.\PhysicalDrive$($vhdxDisk.DiskNumber) /Name:$($cachedVHDXInfo.WindowsRelease)$($cachedVHDXInfo.WindowsVersion)$($shortenedWindowsSKU) /Compress:Default" | Out-Null
WriteLog 'FFU Capture complete'
Dismount-ScratchVhdx -VhdxPath $VHDXPath
}
Expand Down Expand Up @@ -3354,8 +3530,8 @@ Function Get-WindowsVersionInfo {
Invoke-Process reg "load HKLM\FFU $Software" | Out-Null

#Find Windows version values
$SKU = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'EditionID'
WriteLog "Windows SKU: $SKU"
# $WindowsSKU = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'EditionID'
# WriteLog "Windows SKU: $WindowsSKU"
[int]$CurrentBuild = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'CurrentBuild'
WriteLog "Windows Build: $CurrentBuild"
#DisplayVersion does not exist for 1607 builds (RS1 and Server 2016) and Server 2019
Expand All @@ -3366,19 +3542,18 @@ Function Get-WindowsVersionInfo {

$BuildDate = Get-Date -uformat %b%Y

$SKU = switch ($SKU) {
Core { 'Home' }
Professional { 'Pro' }
ProfessionalEducation { 'Pro_Edu' }
Enterprise { 'Ent' }
Education { 'Edu' }
ProfessionalWorkstation { 'Pro_Wks' }
ServerStandard { 'Srv_Std' }
ServerDatacenter { 'Srv_Dtc' }
}
WriteLog "Windows SKU Modified to: $SKU"

if ($SKU -notmatch "Srv") {
F438 # $WindowsSKU = switch ($WindowsSKU) {
# Core { 'Home' }
# Professional { 'Pro' }
# ProfessionalEducation { 'Pro_Edu' }
# Enterprise { 'Ent' }
# Education { 'Edu' }
# ProfessionalWorkstation { 'Pro_Wks' }
# ServerStandard { 'Srv_Std' }
# ServerDatacenter { 'Srv_Dtc' }
# }

if ($shortenedWindowsSKU -notmatch "Srv") {
if ($CurrentBuild -ge 22000) {
$Name = 'Win11'
}
Expand Down Expand Up @@ -3407,7 +3582,7 @@ Function Get-WindowsVersionInfo {
DisplayVersion = $DisplayVersion
BuildDate = $buildDate
Name = $Name
SKU = $SKU
# SKU = $WindowsSKU
}
}
Function Get-USBDrive {
Expand Down Expand Up @@ -4242,7 +4417,8 @@ if (($make -and $model) -and ($installdrivers -or $copydrivers)) {
try {
$adkPath = Get-ADK
#Need to use the Deployment and Imaging tools environment to use dism from the Sept 2023 ADK to optimize FFU
$DandIEnv = "$adkPath`Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"
$DandIEnv = Join-Path $adkPath "Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat"

}
catch {
WriteLog 'ADK not found'
Expand Down Expand Up @@ -4894,6 +5070,11 @@ try {
New-FFU $FFUVM.Name
}
else {
#Shorten Windows SKU for use in FFU file name to remove spaces and long names
WriteLog 'Shortening Windows SKU for FFU file name'
$shortenedWindowsSKU = Get-ShortenedWindowsSKU -WindowsSKU $WindowsSKU
WriteLog "Shortened Windows SKU: $shortenedWindowsSKU"
#Create FFU file
New-FFU
}
}
Expand Down
2 changes: 1 addition & 1 deletion FFUDevelopment/WinPEDeployFFUFiles/ApplyFFU.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ $LogFileName = 'ScriptLog.txt'
$USBDrive = Get-USBDrive
New-item -Path $USBDrive -Name $LogFileName -ItemType "file" -Force | Out-Null
$LogFile = $USBDrive + $LogFilename
$version = '2412.1'
$version = '2412.3'
WriteLog 'Begin Logging'
WriteLog "Script version: $version"

Expand Down
0