mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
Misc Fixes
- Added Get-Childprocesses function to return child processes of parent process - Added a new -Wait boolean parameter to Invoke-Process function. This is to control whether Invoke-Process should wait in order to track stdout and stderr output. This is needed for processes that may hang, waiting for user input and there isn't a way to bypass (some Intel drivers provided by Dell leave dialog windows even when running silently) -Invoke-Process now returns process information (returns $cmd). This allows for process tracking when calling the function. - Since Invoke-Process now returns the process information, also needed to add Out-Null to the majority of the Invoke-Process references to prevent Invoke-Process from writing to the terminal - Refactored a lot of the Get-DellDrivers function due to inconsistencies with how driver extraction behaves between client and server devices. For client, /s /e seemed to work fine, but for server it would only extract the driver installer content and other dell related files, rather than the driver files themselves. We have since switched to using /s /drivers= which will extract the driver content. Not all drivers support /drivers= and may output some information to the terminal that looks like help documentation. If a driver doesn't support /drivers, the script falls back to using /s /e to do the extraction. If this doesn't work for you, you can always provide your own drivers that you manually download from Dell's website. - Updated Malicious Software Removal Tool (MSRT) code to handle Windows Server
This commit is contained in:
+129
-51
@@ -475,6 +475,16 @@ function LogVariableValues {
|
||||
WriteLog 'End logging variables'
|
||||
}
|
||||
|
||||
function Get-ChildProcesses($parentId) {
|
||||
$result = @()
|
||||
$children = Get-CimInstance Win32_Process -Filter "ParentProcessId = $parentId"
|
||||
foreach ($child in $children) {
|
||||
$result += $child
|
||||
$result += Get-ChildProcesses $child.ProcessId
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
function Invoke-Process {
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
param
|
||||
@@ -485,7 +495,11 @@ function Invoke-Process {
|
||||
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$ArgumentList
|
||||
[string]$ArgumentList,
|
||||
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[bool]$Wait = $true
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
@@ -499,7 +513,7 @@ function Invoke-Process {
|
||||
ArgumentList = $ArgumentList
|
||||
RedirectStandardError = $stdErrTempFile
|
||||
RedirectStandardOutput = $stdOutTempFile
|
||||
Wait = $true;
|
||||
Wait = $($Wait);
|
||||
PassThru = $true;
|
||||
NoNewWindow = $true;
|
||||
}
|
||||
@@ -507,7 +521,7 @@ function Invoke-Process {
|
||||
$cmd = Start-Process @startProcessParams
|
||||
$cmdOutput = Get-Content -Path $stdOutTempFile -Raw
|
||||
$cmdError = Get-Content -Path $stdErrTempFile -Raw
|
||||
if ($cmd.ExitCode -ne 0) {
|
||||
if ($cmd.ExitCode -ne 0 -and $wait -eq $true) {
|
||||
if ($cmdError) {
|
||||
throw $cmdError.Trim()
|
||||
}
|
||||
@@ -525,15 +539,14 @@ function Invoke-Process {
|
||||
catch {
|
||||
#$PSCmdlet.ThrowTerminatingError($_)
|
||||
WriteLog $_
|
||||
Write-Host "Script failed - $Logfile for more info"
|
||||
# Write-Host "Script failed - $Logfile for more info"
|
||||
throw $_
|
||||
|
||||
}
|
||||
finally {
|
||||
Remove-Item -Path $stdOutTempFile, $stdErrTempFile -Force -ErrorAction Ignore
|
||||
|
||||
}
|
||||
|
||||
return $cmd
|
||||
}
|
||||
|
||||
function Test-Url {
|
||||
@@ -734,7 +747,7 @@ function Get-MicrosoftDrivers {
|
||||
# Extract the MSI file using an administrative install
|
||||
WriteLog "Extracting MSI file to $modelPath"
|
||||
$arguments = "/a `"$($filePath)`" /qn TARGETDIR=`"$($modelPath)`""
|
||||
Invoke-Process -FilePath "msiexec.exe" -ArgumentList $arguments
|
||||
Invoke-Process -FilePath "msiexec.exe" -ArgumentList $arguments | Out-Null
|
||||
WriteLog "Extraction complete"
|
||||
} elseif ($fileExtension -eq ".zip") {
|
||||
# Extract the ZIP file
|
||||
@@ -790,7 +803,7 @@ function Get-HPDrivers {
|
||||
Start-BitsTransferWithRetry -Source $PlatformListUrl -Destination $PlatformListCab
|
||||
WriteLog "Download complete"
|
||||
WriteLog "Expanding $PlatformListCab to $PlatformListXml"
|
||||
Invoke-Process -FilePath expand.exe -ArgumentList "$PlatformListCab $PlatformListXml"
|
||||
Invoke-Process -FilePath expand.exe -ArgumentList "$PlatformListCab $PlatformListXml" | Out-Null
|
||||
WriteLog "Expansion complete"
|
||||
|
||||
# Parse the PlatformList.xml to find the SystemID based on the ProductName
|
||||
@@ -920,7 +933,7 @@ function Get-HPDrivers {
|
||||
Writelog "Downloading HP Driver cab from $DriverCabUrl to $DriverCabFile"
|
||||
Start-BitsTransferWithRetry -Source $DriverCabUrl -Destination $DriverCabFile
|
||||
WriteLog "Expanding HP Driver cab to $DriverXmlFile"
|
||||
Invoke-Process -FilePath expand.exe -ArgumentList "$DriverCabFile $DriverXmlFile"
|
||||
Invoke-Process -FilePath expand.exe -ArgumentList "$DriverCabFile $DriverXmlFile" | Out-Null
|
||||
|
||||
# Parse the extracted XML file to download individual drivers
|
||||
[xml]$DriverXmlContent = Get-Content -Path $DriverXmlFile
|
||||
@@ -971,7 +984,7 @@ function Get-HPDrivers {
|
||||
# Extract the driver
|
||||
$arguments = "/s /e /f `"$extractFolder`""
|
||||
WriteLog "Extracting driver"
|
||||
Invoke-Process -FilePath $DriverFilePath -ArgumentList $arguments
|
||||
Invoke-Process -FilePath $DriverFilePath -ArgumentList $arguments | Out-Null
|
||||
WriteLog "Driver extracted to: $extractFolder"
|
||||
|
||||
# Delete the .exe driver file after extraction
|
||||
@@ -1181,7 +1194,7 @@ function Get-LenovoDrivers {
|
||||
# Extract the driver
|
||||
# Start-Process -FilePath $driverFilePath -ArgumentList $modifiedExtractCommand -Wait -NoNewWindow
|
||||
WriteLog "Extracting driver: $driverFilePath to $extractFolder"
|
||||
Invoke-Process -FilePath $driverFilePath -ArgumentList $modifiedExtractCommand
|
||||
Invoke-Process -FilePath $driverFilePath -ArgumentList $modifiedExtractCommand | Out-Null
|
||||
WriteLog "Driver extracted"
|
||||
|
||||
# Delete the .exe driver file after extraction
|
||||
@@ -1212,6 +1225,17 @@ function Get-DellDrivers {
|
||||
[int]$WindowsRelease
|
||||
)
|
||||
|
||||
if (-not (Test-Path -Path $DriversFolder)) {
|
||||
WriteLog "Creating Drivers folder: $DriversFolder"
|
||||
New-Item -Path $DriversFolder -ItemType Directory -Force | Out-Null
|
||||
WriteLog "Drivers folder created"
|
||||
}
|
||||
|
||||
$DriversFolder = "$DriversFolder\$Make"
|
||||
WriteLog "Creating Dell Drivers folder: $DriversFolder"
|
||||
New-Item -Path $DriversFolder -ItemType Directory -Force | Out-Null
|
||||
WriteLog "Dell Drivers folder created"
|
||||
|
||||
#CatalogPC.cab is the catalog for Windows client PCs, Catalog.cab is the catalog for Windows Server
|
||||
if ($WindowsRelease -le 11) {
|
||||
$catalogUrl = "http://downloads.dell.com/catalog/CatalogPC.cab"
|
||||
@@ -1231,23 +1255,12 @@ function Get-DellDrivers {
|
||||
exit
|
||||
}
|
||||
|
||||
if (-not (Test-Path -Path $DriversFolder)) {
|
||||
WriteLog "Creating Drivers folder: $DriversFolder"
|
||||
New-Item -Path $DriversFolder -ItemType Directory -Force | Out-Null
|
||||
WriteLog "Drivers folder created"
|
||||
}
|
||||
|
||||
$DriversFolder = "$DriversFolder\$Make"
|
||||
WriteLog "Creating Dell Drivers folder: $DriversFolder"
|
||||
New-Item -Path $DriversFolder -ItemType Directory -Force | Out-Null
|
||||
WriteLog "Dell Drivers folder created"
|
||||
|
||||
WriteLog "Downloading Dell Catalog cab file: $catalogUrl to $DellCabFile"
|
||||
Start-BitsTransferWithRetry -Source $catalogUrl -Destination $DellCabFile
|
||||
WriteLog "Dell Catalog cab file downloaded"
|
||||
|
||||
WriteLog "Extracting Dell Catalog cab file to $DellCatalogXML"
|
||||
Invoke-Process -FilePath Expand.exe -ArgumentList "$DellCabFile $DellCatalogXML"
|
||||
Invoke-Process -FilePath Expand.exe -ArgumentList "$DellCabFile $DellCatalogXML" | Out-Null
|
||||
WriteLog "Dell Catalog cab file extracted"
|
||||
|
||||
$xmlContent = [xml](Get-Content -Path $DellCatalogXML)
|
||||
@@ -1268,6 +1281,8 @@ function Get-DellDrivers {
|
||||
$validOS = $component.SupportedOperatingSystems.OperatingSystem | Where-Object { ($_.osArch -eq $WindowsArch) -and ($_.osCode -match "W19") }
|
||||
} elseif ($WindowsRelease -eq 2022) {
|
||||
$validOS = $component.SupportedOperatingSystems.OperatingSystem | Where-Object { ($_.osArch -eq $WindowsArch) -and ($_.osCode -match "W22") }
|
||||
} elseif ($WindowsRelease -eq 2025) {
|
||||
$validOS = $component.SupportedOperatingSystems.OperatingSystem | Where-Object { ($_.osArch -eq $WindowsArch) -and ($_.osCode -match "W25") }
|
||||
} else {
|
||||
$validOS = $component.SupportedOperatingSystems.OperatingSystem | Where-Object { ($_.osArch -eq $WindowsArch) -and ($_.osCode -match "W22") }
|
||||
}
|
||||
@@ -1277,9 +1292,10 @@ function Get-DellDrivers {
|
||||
$downloadUrl = $baseLocation + $driverPath
|
||||
$driverFileName = [System.IO.Path]::GetFileName($driverPath)
|
||||
$name = $component.Name.Display.'#cdata-section'
|
||||
$name = $name -replace '[\\\/\:\*\?\"\<\>\|]', '_'
|
||||
$name = $name -replace '[\\\/\:\*\?\"\<\>\| ]', '_'
|
||||
$name = $name -replace '[\,]', '-'
|
||||
$category = $component.Category.Display.'#cdata-section'
|
||||
$category = $category -replace '[\\\/\:\*\?\"\<\>\| ]', '_'
|
||||
$version = [version]$component.vendorVersion
|
||||
$namePrefix = ($name -split '-')[0]
|
||||
|
||||
@@ -1327,7 +1343,7 @@ function Get-DellDrivers {
|
||||
$driverFilePath = Join-Path -Path $downloadFolder -ChildPath $driver.DriverFileName
|
||||
|
||||
if (Test-Path -Path $driverFilePath) {
|
||||
Write-Output "Driver already downloaded: $driverFilePath skipping"
|
||||
WriteLog "Driver already downloaded: $driverFilePath skipping"
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1349,13 +1365,66 @@ function Get-DellDrivers {
|
||||
|
||||
|
||||
$extractFolder = $downloadFolder + "\" + $driver.DriverFileName.TrimEnd($driver.DriverFileName[-4..-1])
|
||||
WriteLog "Creating extraction folder: $extractFolder"
|
||||
New-Item -Path $extractFolder -ItemType Directory -Force | Out-Null
|
||||
WriteLog "Extraction folder created"
|
||||
# WriteLog "Creating extraction folder: $extractFolder"
|
||||
# New-Item -Path $extractFolder -ItemType Directory -Force | Out-Null
|
||||
# WriteLog "Extraction folder created"
|
||||
|
||||
# $arguments = "/s /e=`"$extractFolder`""
|
||||
$arguments = "/s /drivers=`"$extractFolder`""
|
||||
WriteLog "Extracting driver: $driverFilePath $arguments"
|
||||
try {
|
||||
#If Category is Chipset, must add -wait $false to the Invoke-Process command line to prevent the script from hanging on the Intel chipset driver which leaves a Window open
|
||||
if ($driver.Category -eq "Chipset") {
|
||||
$process = Invoke-Process -FilePath $driverFilePath -ArgumentList $arguments -Wait $false
|
||||
|
||||
#Wait 5 seconds to allow for the extraction process to finish
|
||||
Start-Sleep -Seconds 5
|
||||
|
||||
$childProcesses = Get-ChildProcesses $process.Id
|
||||
|
||||
# Find and stop the last created child process
|
||||
if ($childProcesses) {
|
||||
$latestProcess = $childProcesses | Sort-Object CreationDate -Descending | Select-Object -First 1
|
||||
Stop-Process -Id $latestProcess.ProcessId -Force
|
||||
# Sleep 1 second to let process finish exiting so its installer can be removed
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
#If Category is Network and $isServer is $false, must add -wait $false to the Invoke-Process command line to prevent the script from hanging on the Intel network driver which leaves a Window open
|
||||
} elseif ($driver.Category -eq "Network" -and $isServer -eq $false) {
|
||||
|
||||
$process = Invoke-Process -FilePath $driverFilePath -ArgumentList $arguments -Wait $false
|
||||
|
||||
#Sometimes the network drivers will extract on client OS, wait 5 seconds and check if the process is still running
|
||||
Start-Sleep -Seconds 5
|
||||
if ($process.HasExited -eq $false) {
|
||||
$childProcesses = Get-ChildProcesses $process.Id
|
||||
|
||||
# Find and stop the last created child process
|
||||
if ($childProcesses) {
|
||||
$latestProcess = $childProcesses | Sort-Object CreationDate -Descending | Select-Object -First 1
|
||||
Stop-Process -Id $latestProcess.ProcessId -Force
|
||||
#Move on to the next driver and skip this one - it won't extract on a client OS even with /s /e switches
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Invoke-Process -FilePath $driverFilePath -ArgumentList $arguments | Out-Null
|
||||
}
|
||||
# If $extractFolder is empty, try alternative extraction method
|
||||
if (!(Get-ChildItem -Path $extractFolder -Recurse | Where-Object { -not $_.PSIsContainer })) {
|
||||
WriteLog 'Extraction with /drivers= switch failed. Removing folder and retrying with /s /e switches'
|
||||
Remove-Item -Path $extractFolder -Force -Recurse -ErrorAction SilentlyContinue
|
||||
$arguments = "/s /e=`"$extractFolder`""
|
||||
WriteLog "Extracting driver: $driverFilePath to $extractFolder"
|
||||
Invoke-Process -FilePath $driverFilePath -ArgumentList $arguments
|
||||
WriteLog "Extracting driver: $driverFilePath $arguments"
|
||||
Invoke-Process -FilePath $driverFilePath -ArgumentList $arguments | Out-Null
|
||||
}
|
||||
}
|
||||
catch {
|
||||
WriteLog 'Extraction with /drivers= switch failed. Retrying with /s /e switches'
|
||||
$arguments = "/s /e=`"$extractFolder`""
|
||||
WriteLog "Extracting driver: $driverFilePath $arguments"
|
||||
Invoke-Process -FilePath $driverFilePath -ArgumentList $arguments | Out-Null
|
||||
}
|
||||
WriteLog "Driver extracted"
|
||||
|
||||
WriteLog "Deleting driver file: $driverFilePath"
|
||||
@@ -1455,7 +1524,7 @@ function Install-ADK {
|
||||
WriteLog "$ADKOption downloaded to $installerLocation"
|
||||
|
||||
WriteLog "Installing $ADKOption with $feature enabled"
|
||||
Invoke-Process $installerLocation "/quiet /installpath ""%ProgramFiles(x86)%\Windows Kits\10"" /features $feature"
|
||||
Invoke-Process $installerLocation "/quiet /installpath ""%ProgramFiles(x86)%\Windows Kits\10"" /features $feature" | Out-Null
|
||||
|
||||
WriteLog "$ADKOption installation completed."
|
||||
WriteLog "Removing $installer from $installerLocation"
|
||||
@@ -1512,7 +1581,7 @@ function Uninstall-ADK {
|
||||
|
||||
$adkBundleCachePath = $adkRegKey.GetValue("BundleCachePath")
|
||||
WriteLog "Uninstalling $ADKOption..."
|
||||
Invoke-Process $adkBundleCachePath "/uninstall /quiet"
|
||||
Invoke-Process $adkBundleCachePath "/uninstall /quiet" | Out-Null
|
||||
WriteLog "$ADKOption uninstalled successfully."
|
||||
}
|
||||
catch {
|
||||
@@ -1615,7 +1684,7 @@ function Get-ADK {
|
||||
if ($adkBundleCachePath) {
|
||||
WriteLog "Installing Windows Deployment Tools..."
|
||||
$adkInstallPath = $adkPath.TrimEnd('\')
|
||||
Invoke-Process $adkBundleCachePath "/quiet /installpath ""$adkInstallPath"" /features OptionId.DeploymentTools"
|
||||
Invoke-Process $adkBundleCachePath "/quiet /installpath ""$adkInstallPath"" /features OptionId.DeploymentTools" | Out-Null
|
||||
WriteLog "Windows Deployment Tools installed successfully."
|
||||
}
|
||||
else {
|
||||
@@ -1668,7 +1737,7 @@ function Get-WindowsESD {
|
||||
# Extract XML from cab file
|
||||
WriteLog "Extracting Products XML from cab"
|
||||
$xmlFilePath = Join-Path $PSScriptRoot "products.xml"
|
||||
Invoke-Process Expand "-F:*.xml $cabFilePath $xmlFilePath"
|
||||
Invoke-Process Expand "-F:*.xml $cabFilePath $xmlFilePath" | Out-Null
|
||||
WriteLog "Products XML extracted"
|
||||
|
||||
# Load XML content
|
||||
@@ -1729,7 +1798,7 @@ function Get-Office {
|
||||
|
||||
# Extract ODT
|
||||
WriteLog "Extracting ODT to $OfficePath"
|
||||
Invoke-Process $ODTInstallFile "/extract:$OfficePath /quiet"
|
||||
Invoke-Process $ODTInstallFile "/extract:$OfficePath /quiet" | Out-Null
|
||||
|
||||
# Run setup.exe with config.xml and modify xml file to download to $OfficePath
|
||||
$ConfigXml = "$OfficePath\DownloadFFU.xml"
|
||||
@@ -1737,7 +1806,7 @@ function Get-Office {
|
||||
$xmlContent.Configuration.Add.SourcePath = $OfficePath
|
||||
$xmlContent.Save($ConfigXml)
|
||||
WriteLog "Downloading M365 Apps/Office to $OfficePath"
|
||||
Invoke-Process $OfficePath\setup.exe "/download $ConfigXml"
|
||||
Invoke-Process $OfficePath\setup.exe "/download $ConfigXml" | Out-Null
|
||||
|
||||
WriteLog "Cleaning up ODT default config files and checking InstallAppsandSysprep.cmd file for proper command line"
|
||||
#Clean up default configuration files
|
||||
@@ -1796,7 +1865,7 @@ function Install-WinGet {
|
||||
# }
|
||||
# $wingetVersion = & winget.exe --version
|
||||
# WriteLog "Installed version of WinGet: $wingetVersion"
|
||||
# if ($wingetVersion -match 'v?(\d+\.\d+\.\d+)' -and [version]$matches[1] -lt $minVersion) {
|
||||
# if ($wingetVersion -match 'v?(\d+\.\d+.\d+)' -and [version]$matches[1] -lt $minVersion) {
|
||||
# WriteLog "The installed version of WinGet $($matches[1]) does not support downloading MSStore apps. Downloading the latest version of WinGet..."
|
||||
# Install-WinGet -Architecture $WindowsArch
|
||||
# }
|
||||
@@ -2415,7 +2484,7 @@ function New-AppsISO {
|
||||
#Create Apps ISO file
|
||||
$OSCDIMG = "$adkpath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe"
|
||||
#Start-Process -FilePath $OSCDIMG -ArgumentList "-n -m -d $Appspath $AppsISO" -wait
|
||||
Invoke-Process $OSCDIMG "-n -m -d $Appspath $AppsISO"
|
||||
Invoke-Process $OSCDIMG "-n -m -d $Appspath $AppsISO" | Out-Null
|
||||
|
||||
#Remove the Office Download and ODT
|
||||
if ($InstallOffice) {
|
||||
@@ -2707,7 +2776,7 @@ function Add-BootFiles {
|
||||
)
|
||||
|
||||
WriteLog "Adding boot files for `"$($OsPartitionDriveLetter):\Windows`" to System partition `"$($SystemPartitionDriveLetter):`"..."
|
||||
Invoke-Process bcdboot "$($OsPartitionDriveLetter):\Windows /S $($SystemPartitionDriveLetter): /F $FirmwareType"
|
||||
Invoke-Process bcdboot "$($OsPartitionDriveLetter):\Windows /S $($SystemPartitionDriveLetter): /F $FirmwareType" | Out-Null
|
||||
WriteLog "Done."
|
||||
}
|
||||
|
||||
@@ -2848,7 +2917,7 @@ function New-PEMedia {
|
||||
elseif($WindowsArch -eq 'arm64') {
|
||||
& cmd /c """$DandIEnv"" && copype arm64 $WinPEFFUPath" | Out-Null
|
||||
}
|
||||
#Invoke-Process cmd "/c ""$DandIEnv"" && copype amd64 $WinPEFFUPath"
|
||||
#Invoke-Process cmd "/c ""$DandIEnv"" && copype amd64 $WinPEFFUPath" | Out-Null
|
||||
WriteLog 'Files copied successfully'
|
||||
|
||||
WriteLog 'Mounting WinPE media to add WinPE optional components'
|
||||
@@ -2944,7 +3013,7 @@ function New-PEMedia {
|
||||
}
|
||||
|
||||
}
|
||||
Invoke-Process $OSCDIMG $OSCDIMGArgs
|
||||
Invoke-Process $OSCDIMG $OSCDIMGArgs | Out-Null
|
||||
WriteLog "ISO created successfully"
|
||||
WriteLog "Cleaning up $WinPEFFUPath"
|
||||
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force
|
||||
@@ -3025,8 +3094,8 @@ function New-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"
|
||||
# Invoke-Process cmd "/c dism /Capture-FFU /ImageFile:$FFUFile /CaptureDrive:\\.\PhysicalDrive$($vhdxDisk.DiskNumber) /Name:$($winverinfo.Name)$($winverinfo.DisplayVersion)$($winverinfo.SKU) /Compress:Default"
|
||||
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 'FFU Capture complete'
|
||||
Dismount-ScratchVhdx -VhdxPath $VHDXPath
|
||||
}
|
||||
@@ -3063,8 +3132,8 @@ function New-FFU {
|
||||
if ($Optimize -eq $true) {
|
||||
WriteLog 'Optimizing FFU - This will take a few minutes, please be patient'
|
||||
#Need to use ADK version of DISM to address bug in DISM - perhaps Windows 11 24H2 will fix this
|
||||
Invoke-Process cmd "/c ""$DandIEnv"" && dism /optimize-ffu /imagefile:$FFUFile"
|
||||
#Invoke-Process cmd "/c dism /optimize-ffu /imagefile:$FFUFile"
|
||||
Invoke-Process cmd "/c ""$DandIEnv"" && dism /optimize-ffu /imagefile:$FFUFile" | Out-Null
|
||||
#Invoke-Process cmd "/c dism /optimize-ffu /imagefile:$FFUFile" | Out-Null
|
||||
WriteLog 'Optimizing FFU complete'
|
||||
}
|
||||
|
||||
@@ -3125,7 +3194,7 @@ function Remove-FFUVM {
|
||||
}
|
||||
#Remove unused mountpoints
|
||||
WriteLog 'Remove unused mountpoints'
|
||||
Invoke-Process cmd "/c mountvol /r"
|
||||
Invoke-Process cmd "/c mountvol /r" | Out-Null
|
||||
WriteLog 'Removal complete'
|
||||
}
|
||||
Function Remove-FFUUserShare {
|
||||
@@ -3145,7 +3214,7 @@ Function Get-WindowsVersionInfo {
|
||||
#Load Registry Hive
|
||||
$Software = "$osPartitionDriveLetter`:\Windows\System32\config\software"
|
||||
WriteLog "Loading Software registry hive"
|
||||
Invoke-Process reg "load HKLM\FFU $Software"
|
||||
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'
|
||||
@@ -3191,7 +3260,7 @@ Function Get-WindowsVersionInfo {
|
||||
}
|
||||
|
||||
WriteLog "Unloading registry"
|
||||
Invoke-Process reg "unload HKLM\FFU"
|
||||
Invoke-Process reg "unload HKLM\FFU" | Out-Null
|
||||
#This prevents Critical Process Died errors you can have during deployment of the FFU. Capturing from very fast disks (NVME) can cause the capture to happen faster than Windows is ready for.
|
||||
WriteLog 'Sleep 60 seconds to allow registry to completely unload'
|
||||
Start-sleep 60
|
||||
@@ -3579,7 +3648,7 @@ function Get-FFUEnvironment {
|
||||
|
||||
# Remove unused mountpoints
|
||||
WriteLog 'Remove unused mountpoints'
|
||||
Invoke-Process cmd "/c mountvol /r"
|
||||
Invoke-Process cmd "/c mountvol /r" | Out-Null
|
||||
WriteLog 'Removal complete'
|
||||
|
||||
# Check for content in the VM folder and delete any folders that start with _FFU-
|
||||
@@ -3622,7 +3691,7 @@ function Get-FFUEnvironment {
|
||||
#Clean up registry
|
||||
if (Test-Path -Path 'HKLM:\FFU') {
|
||||
Writelog 'Found HKLM:\FFU, removing it'
|
||||
Invoke-Process reg "unload HKLM\FFU"
|
||||
Invoke-Process reg "unload HKLM\FFU" | Out-Null
|
||||
}
|
||||
|
||||
#Remove FFU User and Share
|
||||
@@ -4071,8 +4140,17 @@ if ($InstallApps) {
|
||||
if ($UpdateLatestMSRT) {
|
||||
WriteLog "`$UpdateLatestMSRT is set to true."
|
||||
if ($WindowsArch -eq 'x64') {
|
||||
if ($installationType -eq 'client') {
|
||||
$Name = """Windows Malicious Software Removal Tool x64""" + " " + """Windows $WindowsRelease"""
|
||||
}
|
||||
#Windows Server 2025 isn't listed as a product in the Microsoft Update Catalog, so we'll use the 2019 version
|
||||
elseif ($installationType -eq 'server' -and $WindowsRelease -eq '24H2') {
|
||||
$Name = """Windows Malicious Software Removal Tool x64""" + " " + """Windows Server 2019"""
|
||||
}
|
||||
else {
|
||||
$Name = """Windows Malicious Software Removal Tool x64""" + " " + """Windows Server $WindowsRelease"""
|
||||
}
|
||||
}
|
||||
if ($WindowsArch -eq 'x86') {
|
||||
$Name = """Windows Malicious Software Removal Tool""" + " " + """Windows $WindowsRelease"""
|
||||
}
|
||||
@@ -4143,7 +4221,7 @@ if ($InstallApps) {
|
||||
$EdgeMSIFileName = "MicrosoftEdgeEnterprise$WindowsArch.msi"
|
||||
$EdgeFullFilePath = "$EdgePath\$EdgeMSIFileName"
|
||||
WriteLog "Expanding $EdgeCABFilePath"
|
||||
Invoke-Process Expand "$EdgeCABFilePath -F:*.msi $EdgeFullFilePath"
|
||||
Invoke-Process Expand "$EdgeCABFilePath -F:*.msi $EdgeFullFilePath" | Out-Null
|
||||
WriteLog "Expansion complete"
|
||||
|
||||
#Remove Edge CAB file
|
||||
|
||||
Reference in New Issue
Block a user