3535 - The script must be run with elevated privileges to remove provisioned packages and delete specific registry keys.
3636 - The script checks the operating system version to determine whether it is running on Windows 10 or Windows 11 and adjusts the removal process accordingly.
3737#>
38-
39- [CmdletBinding (SupportsShouldProcess = $true , DefaultParameterSetName = " Default" )]
38+ [CmdletBinding (SupportsShouldProcess = $true , DefaultParameterSetName = " Default" , ConfirmImpact = " High" )]
4039param (
4140 [Parameter (Mandatory = $false , ParameterSetName = " Default" )]
4241 [System.Collections.ArrayList ] $SafePackageList = @ (
@@ -52,6 +51,7 @@ param (
5251 " Microsoft.WindowsSoundRecorder_8wekyb3d8bbwe" , # Voice recording app
5352 " Microsoft.WindowsTerminal_8wekyb3d8bbwe" , # Essential terminal app
5453 " Microsoft.MicrosoftEdge.Stable_8wekyb3d8bbwe" , # Microsoft Edge browser
54+ " Microsoft.Edge.GameAssist_8wekyb3d8bbwe" , # Microsoft Edge browser component
5555 " Microsoft.ZuneMusic_8wekyb3d8bbwe" , # Windows Media Player, video and music player
5656
5757 # System applications
@@ -60,12 +60,15 @@ param (
6060 " Microsoft.ApplicationCompatibilityEnhancements_8wekyb3d8bbwe" ,
6161 " Microsoft.SecHealthUI_8wekyb3d8bbwe" ,
6262 " Microsoft.StorePurchaseApp_8wekyb3d8bbwe" ,
63+ " Microsoft.StartExperiencesApp_8wekyb3d8bbwe" ,
6364 " Microsoft.Wallet_8wekyb3d8bbwe" ,
6465 " MicrosoftWindows.CrossDevice_cw5n1h2txyewy" ,
6566 " MicrosoftWindows.Client.WebExperience_cw5n1h2txyewy" ,
66- " Microsoft.WidgetsPlatformRuntime_8wekyb3d8bbwe" ,
67- " MicrosoftCorporationII.WinAppRuntime.Main.1.5_8wekyb3d8bbwe" ,
67+ " Microsoft.WidgetsPlatformRuntime_8wekyb3d8bbwe" , # Ensure policy disables Widgets
6868 " MicrosoftCorporationII.WinAppRuntime.Singleton_8wekyb3d8bbwe" ,
69+ " Microsoft.Winget.Source_8wekyb3d8bbwe" , # Winget package
70+ " Microsoft.WindowsPackageManagerManifestCreator_8wekyb3d8bbwe" , # App to create manifests for winget
71+ " Microsoft.OneDriveSync_8wekyb3d8bbwe" , # OneDrive sync client
6972
7073 # Image & video codecs
7174 " Microsoft.MPEG2VideoExtension_8wekyb3d8bbwe" ,
@@ -78,6 +81,14 @@ param (
7881 " Microsoft.WebMediaExtensions_8wekyb3d8bbwe" ,
7982 " Microsoft.WebpImageExtension_8wekyb3d8bbwe" ),
8083
84+ [Parameter (Mandatory = $false , ParameterSetName = " Default" )]
85+ [System.Collections.ArrayList ] $SafePackageWildCard = @ (
86+ # Packages that include version numbers, so static names aren't effective
87+ " MicrosoftCorporationII.WinAppRuntime.Main*" ,
88+ " Microsoft.WinAppRuntime.DDLM*" ,
89+ " Microsoft.LanguageExperiencePack*" ,
90+ " Microsoft.Teams.SlimCoreVdi*" ),
91+
8192 # Use Targeted switch to remove a targeted list of packages. Useful for in-place feature updates
8293 [Parameter (Mandatory = $false , ParameterSetName = " Targeted" )]
8394 [System.Management.Automation.SwitchParameter ] $Targeted ,
@@ -98,14 +109,31 @@ param (
98109 " Microsoft.XboxGameOverlay_8wekyb3d8bbwe" ,
99110 " Microsoft.XboxIdentityProvider_8wekyb3d8bbwe" ,
100111 " Microsoft.XboxSpeechToTextOverlay_8wekyb3d8bbwe" ,
101- # "MSTeams_8wekyb3d8bbwe",
112+ " MSTeams_8wekyb3d8bbwe" ,
102113 " Microsoft.ZuneVideo_8wekyb3d8bbwe" )
103114)
104115
105116begin {
106- # Get elevated status. if elevated we'll remove packages from all users and provisioned packages
107- $Role = [Security.Principal.WindowsBuiltInRole ] " Administrator"
108- [System.Boolean ] $Elevated = ([Security.Principal.WindowsPrincipal ][Security.Principal.WindowsIdentity ]::GetCurrent()).IsInRole($Role )
117+ # region Functions
118+ function Test-IsOobeComplete {
119+ # https://oofhours.com/2023/09/15/detecting-when-you-are-in-oobe/
120+ $TypeDef = @"
121+ using System;
122+ using System.Text;
123+ using System.Collections.Generic;
124+ using System.Runtime.InteropServices;
125+ namespace Api {
126+ public class Kernel32 {
127+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
128+ public static extern int OOBEComplete(ref int bIsOOBEComplete);
129+ }
130+ }
131+ "@
132+ Add-Type - TypeDefinition $TypeDef - Language " CSharp"
133+ $IsOOBEComplete = $false
134+ [Void ][Api.Kernel32 ]::OOBEComplete([ref ] $IsOOBEComplete )
135+ return [System.Boolean ]$IsOOBEComplete
136+ }
109137
110138 function Add-DeprovisionedPackageKey {
111139 # Explicitly create the registry key for deprovisioned packages
@@ -125,6 +153,15 @@ begin {
125153 Write-Verbose - Message " Failed to create registry key: $Path . Error: $ ( $_.Exception.Message ) "
126154 }
127155 }
156+ # endregion
157+
158+ # Get elevated status. if elevated we'll remove packages from all users and provisioned packages
159+ $Role = [Security.Principal.WindowsBuiltInRole ] " Administrator"
160+ [System.Boolean ] $Elevated = ([Security.Principal.WindowsPrincipal ][Security.Principal.WindowsIdentity ]::GetCurrent()).IsInRole($Role )
161+
162+ if (Test-IsOobeComplete ) {
163+ Write-Warning - Message " OOBE is complete. Removing applications on an existing desktop may remove applications that users rely on."
164+ }
128165}
129166
130167process {
@@ -157,6 +194,15 @@ process {
157194 # Remove all AppX packages, except for packages that can't be removed, frameworks, and the safe packages list
158195 $AppxPackagesToRemove = $AppxPackages | `
159196 Where-Object { $_.NonRemovable -eq $false -and $_.IsFramework -eq $false -and $_.PackageFamilyName -notin $SafePackageList }
197+
198+ # Further filter out packages that match the safe wildcard patterns
199+ $MatchingPackages = $AppxPackagesToRemove | Where-Object {
200+ $Package = $_.PackageFamilyName
201+ $SafePackageWildCard | Where-Object { $Package -like $_ }
202+ }
203+ if ($MatchingPackages ) {
204+ $AppxPackagesToRemove = $AppxPackagesToRemove | Where-Object { $_.PackageFamilyName -notin $MatchingPackages.PackageFamilyName }
205+ }
160206 Write-Verbose - Message " We found $ ( $AppxPackagesToRemove.Count ) packages to remove."
161207
162208 # Check if we're running on Windows 11 or Windows Server 2025, or above
0 commit comments