Add DISM command fallback

This fallback is triggered if an exception occurs while getting information with the cmdlets (I couldn't test this on my host as everything magically works now - sometimes it threw the Class not registered error)
This commit is contained in:
CodingWonders 2024-12-27 09:48:55 +01:00
parent bee4d04a17
commit 9dd508d069
4 changed files with 229 additions and 84 deletions

View File

@ -163,12 +163,12 @@ public class PowerManagement {
} }
Write-Host "Remove Features from the image" Write-Host "Remove Features from the image"
Microwin-RemoveFeatures Microwin-RemoveFeatures -UseCmdlets $true
Write-Host "Removing features complete!" Write-Host "Removing features complete!"
Write-Host "Removing OS packages" Write-Host "Removing OS packages"
Microwin-RemovePackages Microwin-RemovePackages -UseCmdlets $true
Write-Host "Removing Appx Bloat" Write-Host "Removing Appx Bloat"
Microwin-RemoveProvisionedPackages Microwin-RemoveProvisionedPackages -UseCmdlets $true
# Detect Windows 11 24H2 and add dependency to FileExp to prevent Explorer look from going back - thanks @WitherOrNot and @thecatontheceiling # Detect Windows 11 24H2 and add dependency to FileExp to prevent Explorer look from going back - thanks @WitherOrNot and @thecatontheceiling
if ((Microwin-TestCompatibleImage $imgVersion $([System.Version]::new(10,0,26100,1))) -eq $true) { if ((Microwin-TestCompatibleImage $imgVersion $([System.Version]::new(10,0,26100,1))) -eq $true) {

View File

@ -3,38 +3,80 @@ function Microwin-RemoveFeatures() {
.SYNOPSIS .SYNOPSIS
Removes certain features from ISO image Removes certain features from ISO image
.PARAMETER Name .PARAMETER UseCmdlets
No Params Determines whether or not to use the DISM cmdlets for processing.
- If true, DISM cmdlets will be used
- If false, calls to the DISM executable will be made whilst selecting bits and pieces from the output as a string (that was how MicroWin worked before
the DISM conversion to cmdlets)
.EXAMPLE .EXAMPLE
Microwin-RemoveFeatures Microwin-RemoveFeatures -UseCmdlets $true
#> #>
param (
[Parameter(Mandatory = $true, Position = 0)] [bool]$UseCmdlets
)
try { try {
$featlist = (Get-WindowsOptionalFeature -Path $scratchDir) if ($UseCmdlets) {
$featlist = (Get-WindowsOptionalFeature -Path "$scratchDir")
$featlist = $featlist | Where-Object { $featlist = $featlist | Where-Object {
$_.FeatureName -NotLike "*Defender*" -AND $_.FeatureName -NotLike "*Defender*" -AND
$_.FeatureName -NotLike "*Printing*" -AND $_.FeatureName -NotLike "*Printing*" -AND
$_.FeatureName -NotLike "*TelnetClient*" -AND $_.FeatureName -NotLike "*TelnetClient*" -AND
$_.FeatureName -NotLike "*PowerShell*" -AND $_.FeatureName -NotLike "*PowerShell*" -AND
$_.FeatureName -NotLike "*NetFx*" -AND $_.FeatureName -NotLike "*NetFx*" -AND
$_.FeatureName -NotLike "*Media*" -AND $_.FeatureName -NotLike "*Media*" -AND
$_.FeatureName -NotLike "*NFS*" -AND $_.FeatureName -NotLike "*NFS*" -AND
$_.FeatureName -NotLike "*SearchEngine*" -AND $_.FeatureName -NotLike "*SearchEngine*" -AND
$_.FeatureName -NotLike "*RemoteDesktop*" -AND $_.FeatureName -NotLike "*RemoteDesktop*" -AND
$_.State -ne "Disabled" $_.State -ne "Disabled"
}
} else {
$featList = dism /english /image="$scratchDir" /get-features | Select-String -Pattern "Feature Name : " -CaseSensitive -SimpleMatch
if ($?) {
$featList = $featList -split "Feature Name : " | Where-Object {$_}
# Exclude the same items. Note: for now, this doesn't exclude those features that are disabled.
# This will appear in the future
$featList = $featList | Where-Object {
$_ -NotLike "*Defender*" -AND
$_ -NotLike "*Printing*" -AND
$_ -NotLike "*TelnetClient*" -AND
$_ -NotLike "*PowerShell*" -AND
$_ -NotLike "*NetFx*" -AND
$_ -NotLike "*Media*" -AND
$_ -NotLike "*NFS*" -AND
$_ -NotLike "*SearchEngine*" -AND
$_ -NotLike "*RemoteDesktop*"
}
} else {
Write-Host "Features could not be obtained with DISM. MicroWin processing will continue, but features will be skipped."
return
}
} }
foreach($feature in $featlist) { if ($UseCmdlets) {
$status = "Removing feature $($feature.FeatureName)" foreach ($feature in $featList) {
Write-Progress -Activity "Removing features" -Status $status -PercentComplete ($counter++/$featlist.Count*100) $status = "Removing feature $($feature.FeatureName)"
Write-Debug "Removing feature $($feature.FeatureName)" Write-Progress -Activity "Removing features" -Status $status -PercentComplete ($counter++/$featlist.Count*100)
Disable-WindowsOptionalFeature -Path "$scratchDir" -FeatureName $($feature.FeatureName) -Remove -ErrorAction SilentlyContinue -NoRestart Write-Debug "Removing feature $($feature.FeatureName)"
Disable-WindowsOptionalFeature -Path "$scratchDir" -FeatureName $($feature.FeatureName) -Remove -ErrorAction SilentlyContinue -NoRestart
}
} else {
foreach ($feature in $featList) {
$status = "Removing feature $feature"
Write-Progress -Activity "Removing features" -Status $status -PercentComplete ($counter++/$featlist.Count*100)
Write-Debug "Removing feature $feature"
dism /english /image="$scratchDir" /disable-feature /featurename=$feature /remove /quiet /norestart | Out-Null
if ($? -eq $false) {
Write-Host "Feature $feature could not be disabled."
}
}
} }
Write-Progress -Activity "Removing features" -Status "Ready" -Completed Write-Progress -Activity "Removing features" -Status "Ready" -Completed
Write-Host "You can re-enable the disabled features at any time, using either Windows Update or the SxS folder in <installation media>\Sources." Write-Host "You can re-enable the disabled features at any time, using either Windows Update or the SxS folder in <installation media>\Sources."
} catch { } catch {
Write-Host "Unable to get information about the features. MicroWin processing will continue, but features will not be processed" Write-Host "Unable to get information about the features. A fallback will be used..."
Write-Host "Error information: $($_.Exception.Message)" -ForegroundColor Yellow Write-Host "Error information: $($_.Exception.Message)" -ForegroundColor Yellow
Microwin-RemoveFeatures -UseCmdlets $false
} }
} }

View File

@ -1,44 +1,101 @@
function Microwin-RemovePackages { function Microwin-RemovePackages {
<#
.SYNOPSIS
Removes certain packages from ISO image
.PARAMETER UseCmdlets
Determines whether or not to use the DISM cmdlets for processing.
- If true, DISM cmdlets will be used
- If false, calls to the DISM executable will be made whilst selecting bits and pieces from the output as a string (that was how MicroWin worked before
the DISM conversion to cmdlets)
.EXAMPLE
Microwin-RemovePackages -UseCmdlets $true
#>
param (
[Parameter(Mandatory = $true, Position = 0)] [bool]$UseCmdlets
)
try { try {
$pkglist = (Get-WindowsPackage -Path "$scratchDir").PackageName if ($useCmdlets) {
$pkglist = (Get-WindowsPackage -Path "$scratchDir").PackageName
$pkglist = $pkglist | Where-Object { $pkglist = $pkglist | Where-Object {
$_ -NotLike "*ApplicationModel*" -AND $_ -NotLike "*ApplicationModel*" -AND
$_ -NotLike "*indows-Client-LanguagePack*" -AND $_ -NotLike "*indows-Client-LanguagePack*" -AND
$_ -NotLike "*LanguageFeatures-Basic*" -AND $_ -NotLike "*LanguageFeatures-Basic*" -AND
$_ -NotLike "*Package_for_ServicingStack*" -AND $_ -NotLike "*Package_for_ServicingStack*" -AND
$_ -NotLike "*DotNet*" -AND $_ -NotLike "*DotNet*" -AND
$_ -NotLike "*Notepad*" -AND $_ -NotLike "*Notepad*" -AND
$_ -NotLike "*WMIC*" -AND $_ -NotLike "*WMIC*" -AND
$_ -NotLike "*Ethernet*" -AND $_ -NotLike "*Ethernet*" -AND
$_ -NotLike "*Wifi*" -AND $_ -NotLike "*Wifi*" -AND
$_ -NotLike "*FodMetadata*" -AND $_ -NotLike "*FodMetadata*" -AND
$_ -NotLike "*Foundation*" -AND $_ -NotLike "*Foundation*" -AND
$_ -NotLike "*LanguageFeatures*" -AND $_ -NotLike "*LanguageFeatures*" -AND
$_ -NotLike "*VBSCRIPT*" -AND $_ -NotLike "*VBSCRIPT*" -AND
$_ -NotLike "*License*" -AND $_ -NotLike "*License*" -AND
$_ -NotLike "*Hello-Face*" -AND $_ -NotLike "*Hello-Face*" -AND
$_ -NotLike "*ISE*" $_ -NotLike "*ISE*"
}
} else {
$pkgList = dism /english /image="$scratchDir" /get-packages | Select-String -Pattern "Package Identity : " -CaseSensitive -SimpleMatch
if ($?) {
$pkgList = $pkgList -split "Package Identity : " | Where-Object {$_}
# Exclude the same items.
$pkgList = $pkgList | Where-Object {
$_ -NotLike "*ApplicationModel*" -AND
$_ -NotLike "*indows-Client-LanguagePack*" -AND
$_ -NotLike "*LanguageFeatures-Basic*" -AND
$_ -NotLike "*Package_for_ServicingStack*" -AND
$_ -NotLike "*DotNet*" -AND
$_ -NotLike "*Notepad*" -AND
$_ -NotLike "*WMIC*" -AND
$_ -NotLike "*Ethernet*" -AND
$_ -NotLike "*Wifi*" -AND
$_ -NotLike "*FodMetadata*" -AND
$_ -NotLike "*Foundation*" -AND
$_ -NotLike "*LanguageFeatures*" -AND
$_ -NotLike "*VBSCRIPT*" -AND
$_ -NotLike "*License*" -AND
$_ -NotLike "*Hello-Face*" -AND
$_ -NotLike "*ISE*"
}
} else {
Write-Host "Packages could not be obtained with DISM. MicroWin processing will continue, but packages will be skipped."
return
} }
}
$failedCount = 0 if ($UseCmdlets) {
$failedCount = 0
$erroredPackages = [System.Collections.Generic.List[ErroredPackage]]::new() $erroredPackages = [System.Collections.Generic.List[ErroredPackage]]::new()
foreach ($pkg in $pkglist) { foreach ($pkg in $pkglist) {
try { try {
$status = "Removing $pkg" $status = "Removing $pkg"
Write-Progress -Activity "Removing Packages" -Status $status -PercentComplete ($counter++/$pkglist.Count*100) Write-Progress -Activity "Removing Packages" -Status $status -PercentComplete ($counter++/$pkglist.Count*100)
Remove-WindowsPackage -Path "$scratchDir" -PackageName $pkg -NoRestart -ErrorAction SilentlyContinue Remove-WindowsPackage -Path "$scratchDir" -PackageName $pkg -NoRestart -ErrorAction SilentlyContinue
} catch { } catch {
# This can happen if the package that is being removed is a permanent one # This can happen if the package that is being removed is a permanent one
$erroredPackages.Add([ErroredPackage]::new($pkg, $_.Exception.Message)) $erroredPackages.Add([ErroredPackage]::new($pkg, $_.Exception.Message))
$failedCount += 1 $failedCount += 1
continue continue
}
}
} else {
foreach ($package in $pkgList) {
$status = "Removing package $package"
Write-Progress -Activity "Removing features" -Status $status -PercentComplete ($counter++/$featlist.Count*100)
Write-Debug "Removing package $package"
dism /english /image="$scratchDir" /remove-package /packagename=$package /remove /quiet /norestart | Out-Null
if ($? -eq $false) {
Write-Host "Package $package could not be removed."
}
} }
} }
Write-Progress -Activity "Removing Packages" -Status "Ready" -Completed Write-Progress -Activity "Removing Packages" -Status "Ready" -Completed
if ($failedCount -gt 0) if ($UseCmdlets -and $failedCount -gt 0)
{ {
Write-Host "$failedCount package(s) could not be removed. Your image will still work fine, however. Below is information on what packages failed to be removed and why." Write-Host "$failedCount package(s) could not be removed. Your image will still work fine, however. Below is information on what packages failed to be removed and why."
if ($erroredPackages.Count -gt 0) if ($erroredPackages.Count -gt 0)
@ -63,7 +120,8 @@ function Microwin-RemovePackages {
} }
} }
} catch { } catch {
Write-Host "Unable to get information about the packages. MicroWin processing will continue, but packages will not be processed" Write-Host "Unable to get information about the packages. A fallback will be used..."
Write-Host "Error information: $($_.Exception.Message)" -ForegroundColor Yellow Write-Host "Error information: $($_.Exception.Message)" -ForegroundColor Yellow
Microwin-RemovePackages -UseCmdlets $false
} }
} }

View File

@ -3,49 +3,94 @@ function Microwin-RemoveProvisionedPackages() {
.SYNOPSIS .SYNOPSIS
Removes AppX packages from a Windows image during MicroWin processing Removes AppX packages from a Windows image during MicroWin processing
.PARAMETER Name .PARAMETER UseCmdlets
No Params Determines whether or not to use the DISM cmdlets for processing.
- If true, DISM cmdlets will be used
- If false, calls to the DISM executable will be made whilst selecting bits and pieces from the output as a string (that was how MicroWin worked before
the DISM conversion to cmdlets)
.EXAMPLE .EXAMPLE
Microwin-RemoveProvisionedPackages Microwin-RemoveProvisionedPackages
#> #>
param (
[Parameter(Mandatory = $true, Position = 0)] [bool]$UseCmdlets
)
try try
{ {
$appxProvisionedPackages = Get-AppxProvisionedPackage -Path "$($scratchDir)" | Where-Object { if ($UseCmdlets) {
$_.PackageName -NotLike "*AppInstaller*" -AND $appxProvisionedPackages = Get-AppxProvisionedPackage -Path "$($scratchDir)" | Where-Object {
$_.PackageName -NotLike "*Store*" -and $_.PackageName -NotLike "*AppInstaller*" -AND
$_.PackageName -NotLike "*Notepad*" -and $_.PackageName -NotLike "*Store*" -and
$_.PackageName -NotLike "*Printing*" -and $_.PackageName -NotLike "*Notepad*" -and
$_.PackageName -NotLike "*YourPhone*" -and $_.PackageName -NotLike "*Printing*" -and
$_.PackageName -NotLike "*Xbox*" -and $_.PackageName -NotLike "*YourPhone*" -and
$_.PackageName -NotLike "*WindowsTerminal*" -and $_.PackageName -NotLike "*Xbox*" -and
$_.PackageName -NotLike "*Calculator*" -and $_.PackageName -NotLike "*WindowsTerminal*" -and
$_.PackageName -NotLike "*Photos*" -and $_.PackageName -NotLike "*Calculator*" -and
$_.PackageName -NotLike "*VCLibs*" -and $_.PackageName -NotLike "*Photos*" -and
$_.PackageName -NotLike "*Paint*" -and $_.PackageName -NotLike "*VCLibs*" -and
$_.PackageName -NotLike "*Gaming*" -and $_.PackageName -NotLike "*Paint*" -and
$_.PackageName -NotLike "*Extension*" -and $_.PackageName -NotLike "*Gaming*" -and
$_.PackageName -NotLike "*SecHealthUI*" -and $_.PackageName -NotLike "*Extension*" -and
$_.PackageName -NotLike "*ScreenSketch*" $_.PackageName -NotLike "*SecHealthUI*" -and
$_.PackageName -NotLike "*ScreenSketch*"
}
} else {
$appxProvisionedPackages = dism /english /image="$scratchDir" /get-provisionedappxpackages | Select-String -Pattern "PackageName : " -CaseSensitive -SimpleMatch
if ($?) {
$appxProvisionedPackages = $appxProvisionedPackages -split "PackageName : " | Where-Object {$_}
# Exclude the same items.
$appxProvisionedPackages = $appxProvisionedPackages | Where-Object {
$_ -NotLike "*AppInstaller*" -AND
$_ -NotLike "*Store*" -and
$_ -NotLike "*Notepad*" -and
$_ -NotLike "*Printing*" -and
$_ -NotLike "*YourPhone*" -and
$_ -NotLike "*Xbox*" -and
$_ -NotLike "*WindowsTerminal*" -and
$_ -NotLike "*Calculator*" -and
$_ -NotLike "*Photos*" -and
$_ -NotLike "*VCLibs*" -and
$_ -NotLike "*Paint*" -and
$_ -NotLike "*Gaming*" -and
$_ -NotLike "*Extension*" -and
$_ -NotLike "*SecHealthUI*" -and
$_ -NotLike "*ScreenSketch*"
}
} else {
Write-Host "AppX packages could not be obtained with DISM. MicroWin processing will continue, but AppX packages will be skipped."
return
}
} }
$counter = 0 $counter = 0
foreach ($appx in $appxProvisionedPackages) { if ($UseCmdlets) {
$status = "Removing Provisioned $($appx.PackageName)" foreach ($appx in $appxProvisionedPackages) {
Write-Progress -Activity "Removing Provisioned Apps" -Status $status -PercentComplete ($counter++/$appxProvisionedPackages.Count*100) $status = "Removing Provisioned $($appx.PackageName)"
try { Write-Progress -Activity "Removing Provisioned Apps" -Status $status -PercentComplete ($counter++/$appxProvisionedPackages.Count*100)
Remove-AppxProvisionedPackage -Path "$scratchDir" -PackageName $appx.PackageName -ErrorAction SilentlyContinue try {
} catch { Remove-AppxProvisionedPackage -Path "$scratchDir" -PackageName $appx.PackageName -ErrorAction SilentlyContinue
Write-Host "Application $($appx.PackageName) could not be removed" } catch {
continue Write-Host "Application $($appx.PackageName) could not be removed"
continue
}
}
} else {
foreach ($appx in $appxProvisionedPackages) {
$status = "Removing Provisioned $appx"
Write-Progress -Activity "Removing Provisioned Apps" -Status $status -PercentComplete ($counter++/$appxProvisionedPackages.Count*100)
dism /english /image="$scratchDir" /remove-provisionedappxpackage /packagename=$appx /quiet /norestart | Out-Null
if ($? -eq $false) {
Write-Host "AppX package $appx could not be removed."
}
} }
} }
Write-Progress -Activity "Removing Provisioned Apps" -Status "Ready" -Completed Write-Progress -Activity "Removing Provisioned Apps" -Status "Ready" -Completed
} }
catch catch
{ {
# This can happen if getting AppX packages fails Write-Host "Unable to get information about the AppX packages. A fallback will be used..."
Write-Host "Unable to get information about the AppX packages. MicroWin processing will continue, but AppX packages will not be processed"
Write-Host "Error information: $($_.Exception.Message)" -ForegroundColor Yellow Write-Host "Error information: $($_.Exception.Message)" -ForegroundColor Yellow
Microwin-RemoveProvisionedPackages -UseCmdlets $false
} }
} }