前言
由于工作等原因(借口),距离发布上一篇MDT系列的文章已经过去一年 ::twemoji:sweat::
上一章我记录了基于MDT如何使用一个Task即可实现制作Windows基础wim镜像+DIY基础软件+捕捉镜像。传送门
有好多同学一直咨询在制作捕捉镜像的时候遇到的常见的2个问题:
- 如何彻底的移除掉Windows10中内置的应用;
- 手动移除掉一些应用后就无法执行
sysprep
该如何解决;
接下来我会分别用两篇文章去记录我使用的解决方法。本篇将介绍:如何按需移除掉Windows10中内置应用。
环境准备
- Windows 10 Enterprise v22H2.
- MDT环境搭建请参考MDT系列文章,本文将略过此环节
- Office365应用添加请参考自定义Office 365客户端并使用 MDT部署
- 创建模版制作任务请参考MDT部署Windows系列 (十一): 进阶篇—制作完美的Win10 21H2系统镜像模板
本文为 微风 原创文章.经实践,测试,整理发布.如需转载请联系作者获得授权,并注明转载地址.
操作说明
获取内置应用清单
微软在过去几年,几乎每个版本的Windows都会有新增一些新的内置应用。为了便于前后的效果对比,我这里也通过ISO安装一个默认系统。
默认系统安装完成后,手动更新系统补丁
以及Windows Store
应用。
基于微软介绍,Windows内置应用包含以下两种:
官方文档
-
预配应用:
Provisioned Apps
-
系统应用:
System Apps
然后以管理员身份执行powershell,并执行以下命令,即可将系统中所有预配应用的列表列出:
# 获取provisioned-apps
Get-AppxProvisionedPackage -Online | Format-Table DisplayName, PackageName
# 获取system-apps
Get-AppxPackage -PackageTypeFilter Main | ? { $_.SignatureKind -eq "System" } | Sort Name | Format-Table Name, InstallLocation
通过上述方法即可获取到当前系统的所有内置应用,然后将你需要保留的应用名称单独记录下来,后面通过脚本执行除去现有记录的应用外,其他所有内置应用执行卸载操作。
注意:因为不同的Windows版本其内置的应用清单会有所不同,所以我这里做一个需要保留的应用白名单,除白名单外的应用均执行卸载。
卸载脚本
Begin {
# White list of Features On Demand V2 packages
$WhiteListOnDemand = "NetFX3|DirectX|Tools.DeveloperMode.Core|Language|InternetExplorer|ContactSupport|OneCoreUAP|WindowsMediaPlayer|Hello.Face|Notepad|MSPaint|PowerShell.ISE|ShellComponents"
# White list of appx packages to keep installed
$WhiteListedApps = New-Object -TypeName System.Collections.ArrayList
$WhiteListedApps.AddRange(@(
"Microsoft.DesktopAppInstaller",
"Microsoft.Office.OneNote",
"Microsoft.Messaging",
"Microsoft.MSPaint",
"Microsoft.Windows.Photos",
"Microsoft.StorePurchaseApp",
"Microsoft.MicrosoftOfficeHub",
"Microsoft.MicrosoftStickyNotes",
"Microsoft.WindowsAlarms",
"Microsoft.WindowsCalculator",
"Microsoft.WindowsCommunicationsApps", # Mail, Calendar etc
"Microsoft.WindowsSoundRecorder",
"Microsoft.WindowsStore"
))
# Windows 10 version 1809
$WhiteListedApps.AddRange(@(
"Microsoft.ScreenSketch",
"Microsoft.HEIFImageExtension",
"Microsoft.VP9VideoExtensions",
"Microsoft.WebMediaExtensions",
"Microsoft.WebpImageExtension"
))
# Windows 10 version 1909
$WhiteListedApps.AddRange(@(
"Microsoft.Outlook.DesktopIntegrationServicess"
))
# Windows 10 version 2004
$WhiteListedApps.AddRange(@(
"Microsoft.VCLibs.140.00"
))
# Windows 10 version 20H2
$WhiteListedApps.AddRange(@(
"Microsoft.MicrosoftEdge.Stable"
))
# Windows 10 version 2H2
$WhiteListedApps.AddRange(@(
"Microsoft.WindowsCamera",
"Microsoft.YourPhone",
"Microsoft.ZuneMusic",
"Microsoft.ZuneVideo",
"Microsoft.Microsoft3DViewer"
# Add the appname which you want keep here.
))
}
Process {
# Functions
function Write-LogEntry {
param(
[parameter(Mandatory = $true, HelpMessage = "Value added to the RemovedApps.log file.")]
[ValidateNotNullOrEmpty()]
[string]$Value,
[parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")]
[ValidateNotNullOrEmpty()]
[string]$FileName = "RemovedApps.log"
)
# Determine log file location
$LogFilePath = Join-Path -Path $env:windir -ChildPath "Temp$($FileName)"
# Add value to log file
try {
Out-File -InputObject $Value -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop
}
catch [System.Exception] {
Write-Warning -Message "Unable to append log entry to $($FileName) file"
}
}
# Initial logging
Write-LogEntry -Value "Starting built-in AppxPackage, AppxProvisioningPackage and Feature on Demand V2 removal process"
# Determine provisioned apps
$AppArrayList = Get-AppxProvisionedPackage -Online | Select-Object -ExpandProperty DisplayName
# Loop through the list of appx packages
foreach ($App in $AppArrayList) {
Write-LogEntry -Value "Processing appx package: $($App)"
# If application name not in appx package white list, remove AppxPackage and AppxProvisioningPackage
if (($App -in $WhiteListedApps)) {
Write-LogEntry -Value "Skipping excluded application package: $($App)"
}
else {
# Gather package names
$AppPackageFullName = Get-AppxPackage -Name $App | Select-Object -ExpandProperty PackageFullName -First 1
$AppProvisioningPackageName = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $App } | Select-Object -ExpandProperty PackageName -First 1
# Attempt to remove AppxPackage
if ($AppPackageFullName -ne $null) {
try {
Write-LogEntry -Value "Removing AppxPackage: $($AppPackageFullName)"
Remove-AppxPackage -Package $AppPackageFullName -ErrorAction Stop | Out-Null
}
catch [System.Exception] {
Write-LogEntry -Value "Removing AppxPackage '$($AppPackageFullName)' failed: $($_.Exception.Message)"
}
}
else {
Write-LogEntry -Value "Unable to locate AppxPackage for current app: $($App)"
}
# Attempt to remove AppxProvisioningPackage
if ($AppProvisioningPackageName -ne $null) {
try {
Write-LogEntry -Value "Removing AppxProvisioningPackage: $($AppProvisioningPackageName)"
Remove-AppxProvisionedPackage -PackageName $AppProvisioningPackageName -Online -ErrorAction Stop | Out-Null
}
catch [System.Exception] {
Write-LogEntry -Value "Removing AppxProvisioningPackage '$($AppProvisioningPackageName)' failed: $($_.Exception.Message)"
}
}
else {
Write-LogEntry -Value "Unable to locate AppxProvisioningPackage for current app: $($App)"
}
}
}
# Complete
Write-LogEntry -Value "Completed built-in AppxPackage, AppxProvisioningPackage and Feature on Demand V2 removal process"
}
脚本用法
将上述脚本复制并保存到MDT的Scripts
目录中,我的存放在%SCRIPTROOT%CustomRemove-Builtin-AppsInvoke-RemoveBuiltinApps.ps1
该脚本也可以用在SCCM的Task中,具体使用方法请参考下图
执行效果
本篇不再介绍如何捕捉镜像以及过程中创建暂停任务功能,如需可参考上一篇文档。
执行前应用的数量:
任务执行状态:
执行后应用的数量:
日志文件:
后续
至此,已经完成在制作捕捉镜像时移除不需要的系统内置应用的需求。
但如果不出意外(你的环境中服务器、客户端能否访问互联网并且执行了系统更新时
)你将会在Sysprep
过程中遇到如下错误:(
Error SYSPRP Package was installed for a user, but not provisioned for all users. This package will not function properly in the sysprep image.
, Error SYSPRP Failed to remove apps for the current user: 0x80073cf2.
, Error SYSPRP Exit code of RemoveAllApps thread was 0x3cf2.
....
下一篇我将介绍使用多种方式解决因删除或更新包含内置Windows映像的Microsoft Store应用后Sysprep失败的问题。
Enjoy ~~ 🙂
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net