Windows 10启动脚本移除预设App:数组对比问题求助
问题分析与解决方案:Windows 10预装应用移除脚本的数组对比问题
咱们先聊聊你最初脚本里卡壳的地方,然后给出修正方案,顺便说说你后来改的脚本为啥能跑通。
最初脚本的核心问题
你最初的思路是对的:先获取所有预装应用的DisplayName和PackageName,再过滤出在$RemovalList里的项,但两个关键步骤出了问题:
- 对象构建错误:你用
$Apps = "" | select DisplayName,PackageName然后直接把数组赋值给它的属性,这会让$Apps变成单个对象,而不是包含多个应用条目的数组。后续的$array += $Apps完全没起到构建集合的作用。 - 数组对比逻辑错误:你把
$RemovalList赋值给$RemovalList1.DisplayName,然后用Where {$_.DisplayName -eq $RemovalList1.DisplayName}来过滤。这里-eq是用来对比单个值的,而你右边是一个数组,只会返回和数组完全匹配的单个条目(基本不可能),正确的做法应该用-contains或者-in来判断当前DisplayName是否在移除列表里。
修正后的最初思路脚本
下面是调整后的脚本,完美实现你最初的需求:用DisplayName对比过滤,再执行移除:
$RemovalList = @( 'Microsoft.Messaging' 'Microsoft.MicrosoftOfficeHub' 'Microsoft.MicrosoftSolitaireCollection' 'Microsoft.Office.OneNote' 'Microsoft.SkypeApp' 'microsoft.windowscommunicationsapps' 'Microsoft.XboxApp' 'Microsoft.XboxGameOverlay' 'Microsoft.XboxIdentityProvider' 'Microsoft.XboxSpeechToTextOverlay' 'Microsoft.ZuneMusic' 'Microsoft.ZuneVideo' ) # 获取DISM返回的预装应用原始数据 $dismRaw = (DISM /Online /Get-ProvisionedAppxPackages) # 提取PackageName和DisplayName列表 $PNList = ($dismRaw | Select-string PackageName) -replace "PackageName : ", "" $DNList = ($dismRaw | Select-string DisplayName) -replace "DisplayName : ", "" # 构建正确的应用对象数组:每个条目对应一个DisplayName和PackageName $Apps = for ($i=0; $i -lt $DNList.Count; $i++) { [PSCustomObject]@{ DisplayName = $DNList[$i] PackageName = $PNList[$i] } } # 过滤出需要移除的应用(DisplayName在RemovalList中) $AppsToRemove = $Apps | Where-Object { $RemovalList -contains $_.DisplayName } # 循环执行移除命令 $AppsToRemove.PackageName | ForEach-Object { Write-Output "正在移除预装应用: $_" dism /Online /Remove-ProvisionedAppxPackage /PackageName:$_ }
你新脚本的优势说明
你后来改用PackageName前缀匹配的思路非常聪明!因为Windows预装应用的PackageName格式固定为[厂商].[应用名]_[版本]_[架构]_[ID],拆分后第一个部分正好对应DisplayName的核心标识。这个方法反而比直接对比DisplayName更稳定——毕竟有些应用的DisplayName可能存在大小写差异或者本地化后缀,而PackageName的前缀是统一的。
不过要注意,PowerShell的-contains默认不区分大小写,所以你$RemovalList里的小写名称(比如microsoft.windowscommunicationsapps)也能匹配到实际的大写前缀,这点不用担心。
额外补充
关于你提到的Remove-ProvisionedAppxPackage cmdlet在启动脚本中无法运行的问题,确实在OOBE或者早期启动阶段,DISM命令的兼容性更好,因为它是底层系统工具,不依赖PowerShell的某些未完全初始化的组件,所以用DISM命令是更稳妥的选择。
内容的提问来源于stack exchange,提问作者Irenicus




