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:
+131
-53
@@ -475,6 +475,16 @@ function LogVariableValues {
|
|||||||
WriteLog 'End logging variables'
|
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 {
|
function Invoke-Process {
|
||||||
[CmdletBinding(SupportsShouldProcess)]
|
[CmdletBinding(SupportsShouldProcess)]
|
||||||
param
|
param
|
||||||
@@ -485,7 +495,11 @@ function Invoke-Process {
|
|||||||
|
|
||||||
[Parameter()]
|
[Parameter()]
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[string]$ArgumentList
|
[string]$ArgumentList,
|
||||||
|
|
||||||
|
[Parameter()]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[bool]$Wait = $true
|
||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
@@ -499,7 +513,7 @@ function Invoke-Process {
|
|||||||
ArgumentList = $ArgumentList
|
ArgumentList = $ArgumentList
|
||||||
RedirectStandardError = $stdErrTempFile
|
RedirectStandardError = $stdErrTempFile
|
||||||
RedirectStandardOutput = $stdOutTempFile
|
RedirectStandardOutput = $stdOutTempFile
|
||||||
Wait = $true;
|
Wait = $($Wait);
|
||||||
PassThru = $true;
|
PassThru = $true;
|
||||||
NoNewWindow = $true;
|
NoNewWindow = $true;
|
||||||
}
|
}
|
||||||
@@ -507,7 +521,7 @@ function Invoke-Process {
|
|||||||
$cmd = Start-Process @startProcessParams
|
$cmd = Start-Process @startProcessParams
|
||||||
$cmdOutput = Get-Content -Path $stdOutTempFile -Raw
|
$cmdOutput = Get-Content -Path $stdOutTempFile -Raw
|
||||||
$cmdError = Get-Content -Path $stdErrTempFile -Raw
|
$cmdError = Get-Content -Path $stdErrTempFile -Raw
|
||||||
if ($cmd.ExitCode -ne 0) {
|
if ($cmd.ExitCode -ne 0 -and $wait -eq $true) {
|
||||||
if ($cmdError) {
|
if ($cmdError) {
|
||||||
throw $cmdError.Trim()
|
throw $cmdError.Trim()
|
||||||
}
|
}
|
||||||
@@ -525,15 +539,14 @@ function Invoke-Process {
|
|||||||
catch {
|
catch {
|
||||||
#$PSCmdlet.ThrowTerminatingError($_)
|
#$PSCmdlet.ThrowTerminatingError($_)
|
||||||
WriteLog $_
|
WriteLog $_
|
||||||
Write-Host "Script failed - $Logfile for more info"
|
# Write-Host "Script failed - $Logfile for more info"
|
||||||
throw $_
|
throw $_
|
||||||
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
Remove-Item -Path $stdOutTempFile, $stdErrTempFile -Force -ErrorAction Ignore
|
Remove-Item -Path $stdOutTempFile, $stdErrTempFile -Force -ErrorAction Ignore
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return $cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
function Test-Url {
|
function Test-Url {
|
||||||
@@ -734,7 +747,7 @@ function Get-MicrosoftDrivers {
|
|||||||
# Extract the MSI file using an administrative install
|
# Extract the MSI file using an administrative install
|
||||||
WriteLog "Extracting MSI file to $modelPath"
|
WriteLog "Extracting MSI file to $modelPath"
|
||||||
$arguments = "/a `"$($filePath)`" /qn TARGETDIR=`"$($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"
|
WriteLog "Extraction complete"
|
||||||
} elseif ($fileExtension -eq ".zip") {
|
} elseif ($fileExtension -eq ".zip") {
|
||||||
# Extract the ZIP file
|
# Extract the ZIP file
|
||||||
@@ -790,7 +803,7 @@ function Get-HPDrivers {
|
|||||||
Start-BitsTransferWithRetry -Source $PlatformListUrl -Destination $PlatformListCab
|
Start-BitsTransferWithRetry -Source $PlatformListUrl -Destination $PlatformListCab
|
||||||
WriteLog "Download complete"
|
WriteLog "Download complete"
|
||||||
WriteLog "Expanding $PlatformListCab to $PlatformListXml"
|
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"
|
WriteLog "Expansion complete"
|
||||||
|
|
||||||
# Parse the PlatformList.xml to find the SystemID based on the ProductName
|
# 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"
|
Writelog "Downloading HP Driver cab from $DriverCabUrl to $DriverCabFile"
|
||||||
Start-BitsTransferWithRetry -Source $DriverCabUrl -Destination $DriverCabFile
|
Start-BitsTransferWithRetry -Source $DriverCabUrl -Destination $DriverCabFile
|
||||||
WriteLog "Expanding HP Driver cab to $DriverXmlFile"
|
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
|
# Parse the extracted XML file to download individual drivers
|
||||||
[xml]$DriverXmlContent = Get-Content -Path $DriverXmlFile
|
[xml]$DriverXmlContent = Get-Content -Path $DriverXmlFile
|
||||||
@@ -971,7 +984,7 @@ function Get-HPDrivers {
|
|||||||
# Extract the driver
|
# Extract the driver
|
||||||
$arguments = "/s /e /f `"$extractFolder`""
|
$arguments = "/s /e /f `"$extractFolder`""
|
||||||
WriteLog "Extracting driver"
|
WriteLog "Extracting driver"
|
||||||
Invoke-Process -FilePath $DriverFilePath -ArgumentList $arguments
|
Invoke-Process -FilePath $DriverFilePath -ArgumentList $arguments | Out-Null
|
||||||
WriteLog "Driver extracted to: $extractFolder"
|
WriteLog "Driver extracted to: $extractFolder"
|
||||||
|
|
||||||
# Delete the .exe driver file after extraction
|
# Delete the .exe driver file after extraction
|
||||||
@@ -1181,7 +1194,7 @@ function Get-LenovoDrivers {
|
|||||||
# Extract the driver
|
# Extract the driver
|
||||||
# Start-Process -FilePath $driverFilePath -ArgumentList $modifiedExtractCommand -Wait -NoNewWindow
|
# Start-Process -FilePath $driverFilePath -ArgumentList $modifiedExtractCommand -Wait -NoNewWindow
|
||||||
WriteLog "Extracting driver: $driverFilePath to $extractFolder"
|
WriteLog "Extracting driver: $driverFilePath to $extractFolder"
|
||||||
Invoke-Process -FilePath $driverFilePath -ArgumentList $modifiedExtractCommand
|
Invoke-Process -FilePath $driverFilePath -ArgumentList $modifiedExtractCommand | Out-Null
|
||||||
WriteLog "Driver extracted"
|
WriteLog "Driver extracted"
|
||||||
|
|
||||||
# Delete the .exe driver file after extraction
|
# Delete the .exe driver file after extraction
|
||||||
@@ -1212,6 +1225,17 @@ function Get-DellDrivers {
|
|||||||
[int]$WindowsRelease
|
[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
|
#CatalogPC.cab is the catalog for Windows client PCs, Catalog.cab is the catalog for Windows Server
|
||||||
if ($WindowsRelease -le 11) {
|
if ($WindowsRelease -le 11) {
|
||||||
$catalogUrl = "http://downloads.dell.com/catalog/CatalogPC.cab"
|
$catalogUrl = "http://downloads.dell.com/catalog/CatalogPC.cab"
|
||||||
@@ -1231,23 +1255,12 @@ function Get-DellDrivers {
|
|||||||
exit
|
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"
|
WriteLog "Downloading Dell Catalog cab file: $catalogUrl to $DellCabFile"
|
||||||
Start-BitsTransferWithRetry -Source $catalogUrl -Destination $DellCabFile
|
Start-BitsTransferWithRetry -Source $catalogUrl -Destination $DellCabFile
|
||||||
WriteLog "Dell Catalog cab file downloaded"
|
WriteLog "Dell Catalog cab file downloaded"
|
||||||
|
|
||||||
WriteLog "Extracting Dell Catalog cab file to $DellCatalogXML"
|
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"
|
WriteLog "Dell Catalog cab file extracted"
|
||||||
|
|
||||||
$xmlContent = [xml](Get-Content -Path $DellCatalogXML)
|
$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") }
|
$validOS = $component.SupportedOperatingSystems.OperatingSystem | Where-Object { ($_.osArch -eq $WindowsArch) -and ($_.osCode -match "W19") }
|
||||||
} elseif ($WindowsRelease -eq 2022) {
|
} elseif ($WindowsRelease -eq 2022) {
|
||||||
$validOS = $component.SupportedOperatingSystems.OperatingSystem | Where-Object { ($_.osArch -eq $WindowsArch) -and ($_.osCode -match "W22") }
|
$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 {
|
} else {
|
||||||
$validOS = $component.SupportedOperatingSystems.OperatingSystem | Where-Object { ($_.osArch -eq $WindowsArch) -and ($_.osCode -match "W22") }
|
$validOS = $component.SupportedOperatingSystems.OperatingSystem | Where-Object { ($_.osArch -eq $WindowsArch) -and ($_.osCode -match "W22") }
|
||||||
}
|
}
|
||||||
@@ -1277,9 +1292,10 @@ function Get-DellDrivers {
|
|||||||
$downloadUrl = $baseLocation + $driverPath
|
$downloadUrl = $baseLocation + $driverPath
|
||||||
$driverFileName = [System.IO.Path]::GetFileName($driverPath)
|
$driverFileName = [System.IO.Path]::GetFileName($driverPath)
|
||||||
$name = $component.Name.Display.'#cdata-section'
|
$name = $component.Name.Display.'#cdata-section'
|
||||||
$name = $name -replace '[\\\/\:\*\?\"\<\>\|]', '_'
|
$name = $name -replace '[\\\/\:\*\?\"\<\>\| ]', '_'
|
||||||
$name = $name -replace '[\,]', '-'
|
$name = $name -replace '[\,]', '-'
|
||||||
$category = $component.Category.Display.'#cdata-section'
|
$category = $component.Category.Display.'#cdata-section'
|
||||||
|
$category = $category -replace '[\\\/\:\*\?\"\<\>\| ]', '_'
|
||||||
$version = [version]$component.vendorVersion
|
$version = [version]$component.vendorVersion
|
||||||
$namePrefix = ($name -split '-')[0]
|
$namePrefix = ($name -split '-')[0]
|
||||||
|
|
||||||
@@ -1327,7 +1343,7 @@ function Get-DellDrivers {
|
|||||||
$driverFilePath = Join-Path -Path $downloadFolder -ChildPath $driver.DriverFileName
|
$driverFilePath = Join-Path -Path $downloadFolder -ChildPath $driver.DriverFileName
|
||||||
|
|
||||||
if (Test-Path -Path $driverFilePath) {
|
if (Test-Path -Path $driverFilePath) {
|
||||||
Write-Output "Driver already downloaded: $driverFilePath skipping"
|
WriteLog "Driver already downloaded: $driverFilePath skipping"
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1349,13 +1365,66 @@ function Get-DellDrivers {
|
|||||||
|
|
||||||
|
|
||||||
$extractFolder = $downloadFolder + "\" + $driver.DriverFileName.TrimEnd($driver.DriverFileName[-4..-1])
|
$extractFolder = $downloadFolder + "\" + $driver.DriverFileName.TrimEnd($driver.DriverFileName[-4..-1])
|
||||||
WriteLog "Creating extraction folder: $extractFolder"
|
# WriteLog "Creating extraction folder: $extractFolder"
|
||||||
New-Item -Path $extractFolder -ItemType Directory -Force | Out-Null
|
# New-Item -Path $extractFolder -ItemType Directory -Force | Out-Null
|
||||||
WriteLog "Extraction folder created"
|
# WriteLog "Extraction folder created"
|
||||||
|
|
||||||
$arguments = "/s /e=`"$extractFolder`""
|
# $arguments = "/s /e=`"$extractFolder`""
|
||||||
WriteLog "Extracting driver: $driverFilePath to $extractFolder"
|
$arguments = "/s /drivers=`"$extractFolder`""
|
||||||
Invoke-Process -FilePath $driverFilePath -ArgumentList $arguments
|
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 $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 "Driver extracted"
|
||||||
|
|
||||||
WriteLog "Deleting driver file: $driverFilePath"
|
WriteLog "Deleting driver file: $driverFilePath"
|
||||||
@@ -1455,7 +1524,7 @@ function Install-ADK {
|
|||||||
WriteLog "$ADKOption downloaded to $installerLocation"
|
WriteLog "$ADKOption downloaded to $installerLocation"
|
||||||
|
|
||||||
WriteLog "Installing $ADKOption with $feature enabled"
|
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 "$ADKOption installation completed."
|
||||||
WriteLog "Removing $installer from $installerLocation"
|
WriteLog "Removing $installer from $installerLocation"
|
||||||
@@ -1512,7 +1581,7 @@ function Uninstall-ADK {
|
|||||||
|
|
||||||
$adkBundleCachePath = $adkRegKey.GetValue("BundleCachePath")
|
$adkBundleCachePath = $adkRegKey.GetValue("BundleCachePath")
|
||||||
WriteLog "Uninstalling $ADKOption..."
|
WriteLog "Uninstalling $ADKOption..."
|
||||||
Invoke-Process $adkBundleCachePath "/uninstall /quiet"
|
Invoke-Process $adkBundleCachePath "/uninstall /quiet" | Out-Null
|
||||||
WriteLog "$ADKOption uninstalled successfully."
|
WriteLog "$ADKOption uninstalled successfully."
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
@@ -1615,7 +1684,7 @@ function Get-ADK {
|
|||||||
if ($adkBundleCachePath) {
|
if ($adkBundleCachePath) {
|
||||||
WriteLog "Installing Windows Deployment Tools..."
|
WriteLog "Installing Windows Deployment Tools..."
|
||||||
$adkInstallPath = $adkPath.TrimEnd('\')
|
$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."
|
WriteLog "Windows Deployment Tools installed successfully."
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1668,7 +1737,7 @@ function Get-WindowsESD {
|
|||||||
# Extract XML from cab file
|
# Extract XML from cab file
|
||||||
WriteLog "Extracting Products XML from cab"
|
WriteLog "Extracting Products XML from cab"
|
||||||
$xmlFilePath = Join-Path $PSScriptRoot "products.xml"
|
$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"
|
WriteLog "Products XML extracted"
|
||||||
|
|
||||||
# Load XML content
|
# Load XML content
|
||||||
@@ -1729,7 +1798,7 @@ function Get-Office {
|
|||||||
|
|
||||||
# Extract ODT
|
# Extract ODT
|
||||||
WriteLog "Extracting ODT to $OfficePath"
|
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
|
# Run setup.exe with config.xml and modify xml file to download to $OfficePath
|
||||||
$ConfigXml = "$OfficePath\DownloadFFU.xml"
|
$ConfigXml = "$OfficePath\DownloadFFU.xml"
|
||||||
@@ -1737,7 +1806,7 @@ function Get-Office {
|
|||||||
$xmlContent.Configuration.Add.SourcePath = $OfficePath
|
$xmlContent.Configuration.Add.SourcePath = $OfficePath
|
||||||
$xmlContent.Save($ConfigXml)
|
$xmlContent.Save($ConfigXml)
|
||||||
WriteLog "Downloading M365 Apps/Office to $OfficePath"
|
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"
|
WriteLog "Cleaning up ODT default config files and checking InstallAppsandSysprep.cmd file for proper command line"
|
||||||
#Clean up default configuration files
|
#Clean up default configuration files
|
||||||
@@ -1796,7 +1865,7 @@ function Install-WinGet {
|
|||||||
# }
|
# }
|
||||||
# $wingetVersion = & winget.exe --version
|
# $wingetVersion = & winget.exe --version
|
||||||
# WriteLog "Installed version of WinGet: $wingetVersion"
|
# 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..."
|
# WriteLog "The installed version of WinGet $($matches[1]) does not support downloading MSStore apps. Downloading the latest version of WinGet..."
|
||||||
# Install-WinGet -Architecture $WindowsArch
|
# Install-WinGet -Architecture $WindowsArch
|
||||||
# }
|
# }
|
||||||
@@ -2415,7 +2484,7 @@ function New-AppsISO {
|
|||||||
#Create Apps ISO file
|
#Create Apps ISO file
|
||||||
$OSCDIMG = "$adkpath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe"
|
$OSCDIMG = "$adkpath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe"
|
||||||
#Start-Process -FilePath $OSCDIMG -ArgumentList "-n -m -d $Appspath $AppsISO" -wait
|
#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
|
#Remove the Office Download and ODT
|
||||||
if ($InstallOffice) {
|
if ($InstallOffice) {
|
||||||
@@ -2707,7 +2776,7 @@ function Add-BootFiles {
|
|||||||
)
|
)
|
||||||
|
|
||||||
WriteLog "Adding boot files for `"$($OsPartitionDriveLetter):\Windows`" to System partition `"$($SystemPartitionDriveLetter):`"..."
|
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."
|
WriteLog "Done."
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2848,7 +2917,7 @@ function New-PEMedia {
|
|||||||
elseif($WindowsArch -eq 'arm64') {
|
elseif($WindowsArch -eq 'arm64') {
|
||||||
& cmd /c """$DandIEnv"" && copype arm64 $WinPEFFUPath" | Out-Null
|
& 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 'Files copied successfully'
|
||||||
|
|
||||||
WriteLog 'Mounting WinPE media to add WinPE optional components'
|
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 "ISO created successfully"
|
||||||
WriteLog "Cleaning up $WinPEFFUPath"
|
WriteLog "Cleaning up $WinPEFFUPath"
|
||||||
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force
|
Remove-Item -Path "$WinPEFFUPath" -Recurse -Force
|
||||||
@@ -3025,8 +3094,8 @@ function New-FFU {
|
|||||||
WriteLog "FFU file name: $FFUFileName"
|
WriteLog "FFU file name: $FFUFileName"
|
||||||
$FFUFile = "$FFUCaptureLocation\$FFUFileName"
|
$FFUFile = "$FFUCaptureLocation\$FFUFileName"
|
||||||
#Capture the FFU
|
#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 ""$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"
|
# 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'
|
WriteLog 'FFU Capture complete'
|
||||||
Dismount-ScratchVhdx -VhdxPath $VHDXPath
|
Dismount-ScratchVhdx -VhdxPath $VHDXPath
|
||||||
}
|
}
|
||||||
@@ -3063,8 +3132,8 @@ function New-FFU {
|
|||||||
if ($Optimize -eq $true) {
|
if ($Optimize -eq $true) {
|
||||||
WriteLog 'Optimizing FFU - This will take a few minutes, please be patient'
|
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
|
#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 ""$DandIEnv"" && dism /optimize-ffu /imagefile:$FFUFile" | Out-Null
|
||||||
#Invoke-Process cmd "/c dism /optimize-ffu /imagefile:$FFUFile"
|
#Invoke-Process cmd "/c dism /optimize-ffu /imagefile:$FFUFile" | Out-Null
|
||||||
WriteLog 'Optimizing FFU complete'
|
WriteLog 'Optimizing FFU complete'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3125,7 +3194,7 @@ function Remove-FFUVM {
|
|||||||
}
|
}
|
||||||
#Remove unused mountpoints
|
#Remove unused mountpoints
|
||||||
WriteLog 'Remove unused mountpoints'
|
WriteLog 'Remove unused mountpoints'
|
||||||
Invoke-Process cmd "/c mountvol /r"
|
Invoke-Process cmd "/c mountvol /r" | Out-Null
|
||||||
WriteLog 'Removal complete'
|
WriteLog 'Removal complete'
|
||||||
}
|
}
|
||||||
Function Remove-FFUUserShare {
|
Function Remove-FFUUserShare {
|
||||||
@@ -3145,7 +3214,7 @@ Function Get-WindowsVersionInfo {
|
|||||||
#Load Registry Hive
|
#Load Registry Hive
|
||||||
$Software = "$osPartitionDriveLetter`:\Windows\System32\config\software"
|
$Software = "$osPartitionDriveLetter`:\Windows\System32\config\software"
|
||||||
WriteLog "Loading Software registry hive"
|
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
|
#Find Windows version values
|
||||||
$SKU = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'EditionID'
|
$SKU = Get-ItemPropertyValue -Path 'HKLM:\FFU\Microsoft\Windows NT\CurrentVersion\' -Name 'EditionID'
|
||||||
@@ -3191,7 +3260,7 @@ Function Get-WindowsVersionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WriteLog "Unloading registry"
|
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.
|
#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'
|
WriteLog 'Sleep 60 seconds to allow registry to completely unload'
|
||||||
Start-sleep 60
|
Start-sleep 60
|
||||||
@@ -3579,7 +3648,7 @@ function Get-FFUEnvironment {
|
|||||||
|
|
||||||
# Remove unused mountpoints
|
# Remove unused mountpoints
|
||||||
WriteLog 'Remove unused mountpoints'
|
WriteLog 'Remove unused mountpoints'
|
||||||
Invoke-Process cmd "/c mountvol /r"
|
Invoke-Process cmd "/c mountvol /r" | Out-Null
|
||||||
WriteLog 'Removal complete'
|
WriteLog 'Removal complete'
|
||||||
|
|
||||||
# Check for content in the VM folder and delete any folders that start with _FFU-
|
# 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
|
#Clean up registry
|
||||||
if (Test-Path -Path 'HKLM:\FFU') {
|
if (Test-Path -Path 'HKLM:\FFU') {
|
||||||
Writelog 'Found HKLM:\FFU, removing it'
|
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
|
#Remove FFU User and Share
|
||||||
@@ -4071,7 +4140,16 @@ if ($InstallApps) {
|
|||||||
if ($UpdateLatestMSRT) {
|
if ($UpdateLatestMSRT) {
|
||||||
WriteLog "`$UpdateLatestMSRT is set to true."
|
WriteLog "`$UpdateLatestMSRT is set to true."
|
||||||
if ($WindowsArch -eq 'x64') {
|
if ($WindowsArch -eq 'x64') {
|
||||||
$Name = """Windows Malicious Software Removal Tool x64""" + " " + """Windows $WindowsRelease"""
|
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') {
|
if ($WindowsArch -eq 'x86') {
|
||||||
$Name = """Windows Malicious Software Removal Tool""" + " " + """Windows $WindowsRelease"""
|
$Name = """Windows Malicious Software Removal Tool""" + " " + """Windows $WindowsRelease"""
|
||||||
@@ -4143,7 +4221,7 @@ if ($InstallApps) {
|
|||||||
$EdgeMSIFileName = "MicrosoftEdgeEnterprise$WindowsArch.msi"
|
$EdgeMSIFileName = "MicrosoftEdgeEnterprise$WindowsArch.msi"
|
||||||
$EdgeFullFilePath = "$EdgePath\$EdgeMSIFileName"
|
$EdgeFullFilePath = "$EdgePath\$EdgeMSIFileName"
|
||||||
WriteLog "Expanding $EdgeCABFilePath"
|
WriteLog "Expanding $EdgeCABFilePath"
|
||||||
Invoke-Process Expand "$EdgeCABFilePath -F:*.msi $EdgeFullFilePath"
|
Invoke-Process Expand "$EdgeCABFilePath -F:*.msi $EdgeFullFilePath" | Out-Null
|
||||||
WriteLog "Expansion complete"
|
WriteLog "Expansion complete"
|
||||||
|
|
||||||
#Remove Edge CAB file
|
#Remove Edge CAB file
|
||||||
|
|||||||
Reference in New Issue
Block a user