diff --git a/scripts_wip/Win_DieDellCrapware v1.5.ps1 b/scripts_wip/Win_DieDellCrapware v1.5.ps1 new file mode 100644 index 00000000..65b0bb41 --- /dev/null +++ b/scripts_wip/Win_DieDellCrapware v1.5.ps1 @@ -0,0 +1,290 @@ +<# +NOTES + v1.0 10/23/2024 silversword411 initial version + v1.1 10/29/2024 silversword411 Adding old powerdirector apps + v1.2 12/13/2024 silversword411 Removing system apps + v1.3 1/29/2025 silversword411 DellInc.PartnerPromo, DellWatchdogTimer + v1.4 2/9/2025 silversword411 foldercreate and runasuser snippet + v1.5 2/17/2025 silversword411 added Dell Update universal + +#> + +param( + [switch]$debug +) + +{ { foldercreate } } + +if ($debug) { + $DebugPreference = "Continue" +} +else { + $DebugPreference = "SilentlyContinue" + $ErrorActionPreference = 'silentlycontinue' +} + +if (-not ((Get-WmiObject -Class Win32_ComputerSystem).Manufacturer -like "*Dell*")) { + Write-Output "Not a Dell. Exit" + exit 0 +} + +Foldercreate -Paths "$env:ProgramData\TacticalRMM\temp" + +### Uninstall functions + + +Function Remove-App-MSI-QN([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | + Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | + Select-Object -Property DisplayName, UninstallString + + if ($appCheck) { + Write-Host "Uninstalling $($appCheck.DisplayName)" + $uninstallCommand = $appCheck.UninstallString -replace "/I", "/X" + $uninstallCommand += " /quiet /norestart" + + try { + Start-Process -FilePath "cmd.exe" -ArgumentList "/c $uninstallCommand" -Wait + Write-Host "$($appCheck.DisplayName) uninstalled successfully." + } + catch { + Write-Error "Failed to uninstall $($appCheck.DisplayName). Error: $_" + } + } + else { + Write-Host "$appName is not installed on this computer." + } +} + + +Function Remove-App-EXE-SILENT([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString + " -silent" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App-MSI_EXE-Quiet([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString[1] + " /qn /restart" + cmd /c $uninst + + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App-MSI_EXE-S([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString[1] + " /S" + cmd /c $uninst + + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App-MSI-I-QN([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString.Replace("/I", "/X") + " /qn /norestart" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App([String]$appName) { + $app = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like $appName } + if ($app) { + foreach ($package in $app) { + $packageFullName = $package.PackageFullName + Write-Host "Uninstalling $appName ($packageFullName)" + Remove-AppxPackage -Package $packageFullName -AllUsers + } + + $provApp = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $appName } + if ($provApp) { + foreach ($provisionedPackage in $provApp) { + $proPackageFullName = $provisionedPackage.PackageName + Write-Host "Uninstalling provisioned $appName ($proPackageFullName)" + Remove-AppxProvisionedPackage -Online -PackageName $proPackageFullName + } + } + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-System-App([String]$appName) { + # Remove installed appx packages for all users + $appMatches = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like $appName } + if ($appMatches) { + foreach ($app in $appMatches) { + $packageFullName = $app.PackageFullName + Write-Host "Uninstalling installed system app: $appName ($packageFullName)" + try { + Remove-AppxPackage -Package $packageFullName -AllUsers + } + catch { + Write-Error "Failed to remove installed package: $packageFullName. Error: $_" + } + } + } + else { + Write-Host "$appName is not installed for any user." + } + + # Remove provisioned appx packages + $provAppMatches = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $appName } + if ($provAppMatches) { + foreach ($provApp in $provAppMatches) { + $provPackageFullName = $provApp.PackageName + Write-Host "Uninstalling provisioned system app: $appName ($provPackageFullName)" + try { + Remove-AppxProvisionedPackage -Online -PackageName $provPackageFullName + } + catch { + Write-Error "Failed to remove provisioned package: $provPackageFullName. Error: $_" + } + } + } + else { + Write-Host "$appName is not provisioned on this computer." + } +} + + +Function Check-UninstallString([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host $appCheck.DisplayName $appCheck.UninstallString + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App-EXE-S-QUOTES([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = "`"" + $appCheck.UninstallString + "`"" + " /S" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Debug-AppInfo([String]$appName) { + Write-Host "DEBUG: Checking for app: $appName" + + # Check installed AppxPackage for all users + $appMatches = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like $appName } + if ($appMatches) { + Write-Host "Installed AppxPackages found:" + $appMatches | Format-Table -Property Name, PackageFullName, Publisher + } + else { + Write-Host "No installed AppxPackages found matching: $appName" + } + + # Check provisioned packages + $provAppMatches = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $appName } + if ($provAppMatches) { + Write-Host "Provisioned AppxPackages found:" + $provAppMatches | Format-Table -Property DisplayName, PackageName + } + else { + Write-Host "No provisioned AppxPackages found matching: $appName" + } + + # Check MSI/EXE installations in registry + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | + Get-ItemProperty | Where-Object { $_.DisplayName -like "*$appName*" } + if ($appCheck) { + Write-Host "MSI/EXE installations found in registry:" + $appCheck | Format-Table -Property DisplayName, UninstallString + } + else { + Write-Host "No MSI/EXE installations found in registry matching: $appName" + } +} + + +Remove-App-MSI-I-QN "Dell Trusted Device Agent" +Remove-App-MSI-QN "Dell Update for Windows Universal" +Remove-App-EXE-S-QUOTES "Dell Pair" +Remove-App-MSI-QN "Dell SupportAssist" +Remove-App-MSI-QN "Dell Digital Delivery" +Remove-App-MSI_EXE-S "Dell SupportAssist Remediation" +Remove-App "DellInc.DellDigitalDelivery" +Remove-App "*DellInc.DellCustomerConnect" +Remove-App "*DellInc.PartnerPromo" +Remove-App "*DellWatchdogTimer" +#Remove-App "*DellInc.MyDell" +Remove-App "DellInc.DellUpdate" +Remove-App "DB6EA5DB.PowerMediaPlayerforDell" +Remove-App "DB6EA5DB.Power2GoforDell" +Remove-App "DB6EA5DB.PowerDirectorforDell" +Remove-App "DB6EA5DB.MediaSuiteEssentialsforDell" +Remove-App-MSI-QN "Dell Digital Delivery Services" +Remove-App-EXE-S-QUOTES "Dell Display Manager 2.2" +Remove-App-EXE-S-QUOTES "Dell Peripheral Manager" +Remove-App-MSI-I-QN "Dell Core Services" +# Remove-App-MSI-I-QN "Dell Optimizer" Doesn't work on EHILL2025 +# Remove-App-EXE-S-QUOTES "MyDell" Doesn't work on EHILL2025 not a silent uninstaller and linked with Optimizer +Remove-System-App "5A894077.McAfeeSecurity" +Remove-System-App "DellInc.DellProductRegistration" +#Debug-AppInfo "Dell Digital Delivery" + +if ($debug) { + Write-Output "***************** Debugging info *****************" + + Write-Output "`n==== Debug: All Uninstall Items (Wrapped Table) ====" + Get-ItemProperty ` + HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* ` + -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName } | + Sort-Object DisplayName | + Select-Object DisplayName, UninstallString, Publisher | + Format-Table -AutoSize -Wrap + + + Write-Output "`n==== List of User Apps (Appx) from System (-AllUsers) ====" + Get-AppxPackage -AllUsers | + Sort-Object -Property Name | + Format-Table Name, + @{Label = "Publisher"; Expression = { $_.Publisher.Substring(0, [Math]::Min(20, $_.Publisher.Length)) } } + + Write-Output "`n==== List of System Apps (Provisioned) ====" + Get-AppxProvisionedPackage -Online | + Sort-Object -Property DisplayName | + Format-Table DisplayName, + @{Label = "Publisher"; Expression = { $_.Publisher.Substring(0, [Math]::Min(20, $_.Publisher.Length)) } } +} diff --git a/scripts_wip/Win_DieHPCrapware v1.5.ps1 b/scripts_wip/Win_DieHPCrapware v1.5.ps1 new file mode 100644 index 00000000..83dffb5e --- /dev/null +++ b/scripts_wip/Win_DieHPCrapware v1.5.ps1 @@ -0,0 +1,307 @@ +<# +NOTES + 1.0 10/23/2024 silversword411 initial version + 1.1 1/3/2025 silversword411 Adding debug and kill Touchpoint analytics + 1.2 2/9/2025 silversword411 foldercreate and runasuser snippet + 1.3 2/9/2025 silversword411 added Remove-provisionedapp, added some apps, fixed Remove-App + 1.4 9/2/2025 silversword411 added HP enhanced Lighting + 1.5 1/9/2026 silversword411 expanded HP/Poly bloatware removal (HP Sure*, Notifications, Poly Lens/Camera), added targeted HP service disablement, and enhanced debug visibility for HP services + +#> + +param( + [switch]$debug +) + +{ { foldercreate } } +{ { runasuser } } + +if ($debug) { + $DebugPreference = "Continue" +} +else { + $DebugPreference = "SilentlyContinue" + $ErrorActionPreference = 'silentlycontinue' +} + +$manufacturer = (Get-WmiObject -Class Win32_ComputerSystem).Manufacturer + +if (-not ($manufacturer -like "*HP*" -or $manufacturer -like "*Hewlett-Packard*")) { + Write-Output "Not an HP. Exiting." + Write-Output "Manufacturer detected: $manufacturer" + exit 0 +} + +Foldercreate -Paths "$env:ProgramData\TacticalRMM\temp" + +### Uninstall functions + +Function Remove-App-MSI-QN([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString + " /qn /norestart" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-EXE-SILENT([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString + " -silent" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-MSI_EXE-Quiet([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString[1] + " /qn /restart" + cmd /c $uninst + + } + else { + Write-Host "$appName is not installed on this computer" + } +} +Function Remove-App-MSI_EXE-S([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString[1] + " /S" + cmd /c $uninst + + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-MSI-I-QN([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString.Replace("/I", "/X") + " /qn /norestart" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App([String]$appName) { + $app = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like $appName } + if ($app) { + foreach ($package in $app) { + Write-Host "Uninstalling $($package.Name)" + Remove-AppxPackage -Package $package.PackageFullName -AllUsers + } + $provApp = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $appName } + if ($provApp) { + foreach ($proPackage in $provApp) { + Write-Host "Uninstalling provisioned $($proPackage.DisplayName)" + Remove-AppxProvisionedPackage -Online -PackageName $proPackage.PackageName -AllUsers + } + } + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-ProvisionedApp([String]$appName) { + $provApp = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $appName } + if ($provApp) { + foreach ($proPackage in $provApp) { + Write-Host "Removing provisioned package: $($proPackage.DisplayName)" + Remove-AppxProvisionedPackage -Online -PackageName $proPackage.PackageName -ErrorAction SilentlyContinue + } + } + else { + Write-Host "$appName is not provisioned on this computer" + } +} + + +Function Check-UninstallString([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host $appCheck.DisplayName $appCheck.UninstallString + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-EXE-S-QUOTES([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = "`"" + $appCheck.UninstallString + "`"" + " /S" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-MSI-ByName-QN([string]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | + Get-ItemProperty | + Where-Object { $_.DisplayName -eq $appName } | + Select-Object -First 1 -Property DisplayName, UninstallString + + if (-not $appCheck) { + Write-Host "$appName is not installed on this computer" + return + } + + $u = $appCheck.UninstallString + if ($u -is [array]) { $u = $u | Select-Object -First 1 } + + # Pull the product code out of the uninstall string + if ($u -match '\{[0-9A-Fa-f\-]{36}\}') { + $guid = $matches[0] + Write-Host "Uninstalling $($appCheck.DisplayName) ($guid)" + Start-Process -FilePath "msiexec.exe" -ArgumentList "/x$guid /qn /norestart" -Wait + } + else { + Write-Host "Uninstall string for $($appCheck.DisplayName) does not look like an MSI GUID: $u" + } +} + + +Remove-App "*McAfeeWPSSparsePackage" +Remove-App "AD2F1837.myHP" +Remove-App "AD2F1837.HPSystemEventUtility" +Remove-App "AD2F1837.OMENCommandCenter" +Remove-App "AD2F1837.HPSystemInformation" +Remove-App "C27EB4BA.DropboxOEM" +Remove-App "PricelinePartnerNetwork*" +Remove-App "*McAfeeSecurity" +Remove-App "*HPJumpStarts" +Remove-App "*HPInc.EnergyStar" +Remove-App "*HPPrivacySettings" +Remove-ProvisionedApp "*Dropbox*" +Remove-ProvisionedApp "*HPPrinterControl" +Remove-ProvisionedApp "*HPPrivacySettings" +Remove-ProvisionedApp "*HPSupportAssistant" +Remove-App "AD2F1837.HPEnhance" +Remove-ProvisionedApp "AD2F1837.HPEnhance" +Remove-App-MSI-ByName-QN "HP Sure Recover" +Remove-App-MSI-QN "HP Sure Run Module" +Remove-App-MSI-QN "HP Notifications" +Remove-App-MSI-QN "Poly Lens Desktop" +Remove-App-MSI-I-QN "Poly Lens Control Service" +Remove-App-MSI-QN "Poly Camera Pro Compatibility Add-on" + +## Manually Kill services + +# HP Services Scan +Stop-Service -Name "hpsvcsscan" -ErrorAction SilentlyContinue +Set-Service -Name "hpsvcsscan" -StartupType Disabled -ErrorAction SilentlyContinue + +# HP SFU Service +Stop-Service -Name "SFUService" -ErrorAction SilentlyContinue +Set-Service -Name "SFUService" -StartupType Disabled -ErrorAction SilentlyContinue + +# Optional: HP Audio Analytics +Stop-Service -Name "HPAudioAnalytics" -ErrorAction SilentlyContinue +Set-Service -Name "HPAudioAnalytics" -StartupType Disabled -ErrorAction SilentlyContinue + +# Optional: HP Hotkey UWP +Stop-Service -Name "HotKeyServiceUWP" -ErrorAction SilentlyContinue +Set-Service -Name "HotKeyServiceUWP" -StartupType Disabled -ErrorAction SilentlyContinue + +# Optional: HP LAN/WLAN/WWAN Switching +Stop-Service -Name "LanWlanWwanSwitchingServiceUWP" -ErrorAction SilentlyContinue +Set-Service -Name "LanWlanWwanSwitchingServiceUWP" -StartupType Disabled -ErrorAction SilentlyContinue + + +## Remove via AppX SYSTEM +$Bloatware = @( + # Unnecessary Windows 10 AppX Apps + #"*DellInc.DellCustomerConnect" +) + +foreach ($Bloat in $Bloatware) { + Get-AppxPackage -Name $Bloat | Remove-AppxPackage + # This is system wide provisioned packages + Get-AppxProvisionedPackage -Online | Where-Object DisplayName -like $Bloat | Remove-AppxProvisionedPackage -Online + Write-Output "Trying to remove $Bloat." +} + +# Kill TouchpointAnalytics +Stop-Service -Name "HpTouchpointAnalyticsService" +Set-Service -Name "HpTouchpointAnalyticsService" -StartupType Disabled +#Remove-Service -Name "HpTouchpointAnalyticsService" +& sc.exe delete "HpTouchpointAnalyticsService" +Remove-Item -Path "C:\ProgramData\HP\HP Touchpoint Analytics Client\" -Recurse -Force +Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{E5FB98E0-0784-44F0-8CEC-95CD4690C43F}" -Recurse + +if ($Debug) { + Write-Output "***************** Debugging info *****************" + Write-Output "List of User apps from system" + Get-AppxPackage | Sort-Object -Property Name | + Format-Table Name, @{Label = "Publisher"; Expression = { $_.Publisher.Substring(0, [Math]::Min(20, $_.Publisher.Length)) } } + + Write-Output "List of System apps" + Get-AppxProvisionedPackage -Online | Sort-Object -Property DisplayName | + Format-Table DisplayName, @{Label = "Publisher"; Expression = { $_.Publisher.Substring(0, [Math]::Min(20, $_.Publisher.Length)) } } + + # Define registry paths to check for installed programs + $registryPaths = @( + 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', + 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' + ) + + # Collect installed programs and their uninstall strings + $installedPrograms = foreach ($path in $registryPaths) { + Get-ItemProperty -Path $path | + Where-Object { $_.DisplayName -and $_.UninstallString } | + ForEach-Object { + "Display Name: $($_.DisplayName)" + "Uninstall String: $($_.UninstallString)" + "" + } + } + + # Display the list + $installedPrograms + + # -------- HP Services dump (for deciding what to clean up) -------- + Write-Output "" + Write-Output "================ HP SERVICES (Debug) ================" + + Get-Service | + Where-Object { + $_.Name -match '(?i)^hp|hp' -or + $_.DisplayName -match '(?i)^hp|hp' + } | + Sort-Object DisplayName | + ForEach-Object { + $svc = $_ + $regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$($svc.Name)" + $imagePath = (Get-ItemProperty $regPath -ErrorAction SilentlyContinue).ImagePath + + [PSCustomObject]@{ + Name = $svc.Name + DisplayName = $svc.DisplayName + Status = $svc.Status + StartType = $svc.StartType + ImagePath = $imagePath + } + } | + Out-String -Width 4096 | + Write-Output + +} diff --git a/scripts_wip/Win_DieLenovoCrapware v1.5.ps1 b/scripts_wip/Win_DieLenovoCrapware v1.5.ps1 new file mode 100644 index 00000000..a9a48abb --- /dev/null +++ b/scripts_wip/Win_DieLenovoCrapware v1.5.ps1 @@ -0,0 +1,424 @@ +<# +NOTES + v1.0 2/26/2025 silversword411 initial version + v1.1 2/28/2025 silversword411 adding driver removers + v1.2 5/14/2025 silversword411 Made driver removers a function and test param + v1.3 7/3/2025 silversword411 adding Universal Device Client Service, Lenovo Fn and function keys service, Lenovo Notebook ITS Service + v1.4 8/5/2025 silversword411 trackpoint menu +#> + +param( + [switch]$debug, + [switch]$pnpTest +) + +{ { foldercreate } } + +if ($debug) { + $DebugPreference = "Continue" +} +else { + $DebugPreference = "SilentlyContinue" + $ErrorActionPreference = 'silentlycontinue' +} + +if (-not ((Get-WmiObject -Class Win32_ComputerSystem).Manufacturer -like "*Lenovo*")) { + Write-Output "Not a Lenovo. Exiting." + exit 0 +} + +Foldercreate -Paths "$env:ProgramData\TacticalRMM\temp" + +### Uninstall functions + + +Function Remove-App-MSI-QN([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | + Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | + Select-Object -Property DisplayName, UninstallString + + if ($appCheck) { + Write-Host "Uninstalling $($appCheck.DisplayName)" + $uninstallCommand = $appCheck.UninstallString -replace "/I", "/X" + $uninstallCommand += " /quiet /norestart" + + try { + Start-Process -FilePath "cmd.exe" -ArgumentList "/c $uninstallCommand" -Wait + Write-Host "$($appCheck.DisplayName) uninstalled successfully." + } + catch { + Write-Error "Failed to uninstall $($appCheck.DisplayName). Error: $_" + } + } + else { + Write-Host "$appName is not installed on this computer." + } +} + + +Function Remove-App-EXE-SILENT([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString + " -silent" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App-MSI_EXE-Quiet([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString[1] + " /qn /restart" + cmd /c $uninst + + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App-MSI_EXE-S([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString[1] + " /S" + cmd /c $uninst + + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App-MSI-I-QN([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = $appCheck.UninstallString.Replace("/I", "/X") + " /qn /norestart" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App([String]$appName) { + $app = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like $appName } + if ($app) { + foreach ($package in $app) { + $packageFullName = $package.PackageFullName + Write-Host "Uninstalling $appName ($packageFullName)" + Remove-AppxPackage -Package $packageFullName -AllUsers + } + + $provApp = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $appName } + if ($provApp) { + foreach ($provisionedPackage in $provApp) { + $proPackageFullName = $provisionedPackage.PackageName + Write-Host "Uninstalling provisioned $appName ($proPackageFullName)" + Remove-AppxProvisionedPackage -Online -PackageName $proPackageFullName + } + } + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-System-App([String]$appName) { + # Remove installed appx packages for all users + $appMatches = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like $appName } + if ($appMatches) { + foreach ($app in $appMatches) { + $packageFullName = $app.PackageFullName + Write-Host "Uninstalling installed system app: $appName ($packageFullName)" + try { + Remove-AppxPackage -Package $packageFullName -AllUsers + } + catch { + Write-Error "Failed to remove installed package: $packageFullName. Error: $_" + } + } + } + else { + Write-Host "$appName is not installed for any user." + } + + # Remove provisioned appx packages + $provAppMatches = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $appName } + if ($provAppMatches) { + foreach ($provApp in $provAppMatches) { + $provPackageFullName = $provApp.PackageName + Write-Host "Uninstalling provisioned system app: $appName ($provPackageFullName)" + try { + Remove-AppxProvisionedPackage -Online -PackageName $provPackageFullName + } + catch { + Write-Error "Failed to remove provisioned package: $provPackageFullName. Error: $_" + } + } + } + else { + Write-Host "$appName is not provisioned on this computer." + } +} + + +Function Check-UninstallString([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host $appCheck.DisplayName $appCheck.UninstallString + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Remove-App-EXE-S-QUOTES([String]$appName) { + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object { $_.DisplayName -eq $appName } | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling "$appCheck.DisplayName + $uninst = "`"" + $appCheck.UninstallString + "`"" + " /S" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + + +Function Debug-AppInfo([String]$appName) { + Write-Host "DEBUG: Checking for app: $appName" + + # Check installed AppxPackage for all users + $appMatches = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like $appName } + if ($appMatches) { + Write-Host "Installed AppxPackages found:" + $appMatches | Format-Table -Property Name, PackageFullName, Publisher + } + else { + Write-Host "No installed AppxPackages found matching: $appName" + } + + # Check provisioned packages + $provAppMatches = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $appName } + if ($provAppMatches) { + Write-Host "Provisioned AppxPackages found:" + $provAppMatches | Format-Table -Property DisplayName, PackageName + } + else { + Write-Host "No provisioned AppxPackages found matching: $appName" + } + + # Check MSI/EXE installations in registry + $appCheck = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | + Get-ItemProperty | Where-Object { $_.DisplayName -like "*$appName*" } + if ($appCheck) { + Write-Host "MSI/EXE installations found in registry:" + $appCheck | Format-Table -Property DisplayName, UninstallString + } + else { + Write-Host "No MSI/EXE installations found in registry matching: $appName" + } +} + +Remove-App "*LenovoCompanion*" +#Remove-AppxProvisionedPackage -Online -PackageName "*LenovoCompanion*" +Remove-App "*LenovoUtility*" +Remove-App "E0469640.TrackPointQuickMenu" +Remove-App "MirametrixInc.GlancebyMirametrix" +Remove-App "*LenovoSmartCommunication" + +#Get-Service -Name ImControllerService +$lenovoNowUninstaller = "C:\Program Files (x86)\Lenovo\LenovoNow\unins000.exe" +if (Test-Path $lenovoNowUninstaller) { + Start-Process -FilePath $lenovoNowUninstaller -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" -Wait -NoNewWindow +} +else { + Write-Host "Lenovo Now uninstaller not found at $lenovoNowUninstaller" +} + +$lenovoSmartMeetingUninstaller = "C:\Program Files\Lenovo\Lenovo Smart Meeting Components\unins000.exe" +if (Test-Path $lenovoSmartMeetingUninstaller) { + Start-Process -FilePath $lenovoSmartMeetingUninstaller -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" -Wait -NoNewWindow +} +else { + Write-Host "Lenovo Smart Meeting Components uninstaller not found at $lenovoSmartMeetingUninstaller" +} + +<# +# https://pcsupport.lenovo.com/us/en/products/desktops-and-all-in-ones/thinkcentre-m-series-desktops/thinkcentre-m90/solutions/ht513363 +# pnputil /enum-drivers >c:\driver.log +pnputil /delete-driver oem0.inf /uninstall +pnputil /delete-driver oem51.inf /uninstall +pnputil /delete-driver oem61.inf /uninstall +pnputil /delete-driver oem49.inf /uninstall +pnputil /delete-driver oem1.inf /uninstall +pnputil /delete-driver oem53.inf /uninstall +pnputil /delete-driver oem54.inf /uninstall +pnputil /delete-driver oem50.inf /uninstall +pnputil /delete-driver oem57.inf /uninstall +pnputil /delete-driver oem41.inf /uninstall +#> + +# Disable Lenovo Notebook ITS Service +Stop-Service -Name LITSSVC -Force +Set-Service -Name LITSSVC -StartupType Disabled + +# Disable Lenovo Fn and function keys service +# Disable Lenovo Fn and function keys service +$serviceName = "LenovoFnAndFunctionKeys" +$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue + +if ($service) { + if ($service.Status -eq "Running") { + Write-Host "Stopping $serviceName service..." + Stop-Service -Name $serviceName -Force + } + Write-Host "Disabling $serviceName service..." + Set-Service -Name $serviceName -StartupType Disabled +} +else { + Write-Host "$serviceName service not found." +} + +# UDCService Universal Device Client Service +Stop-Service -Name UDCService -Force +Set-Service -Name UDCService -StartupType Disabled + +# YMC Lenovo Yoga Mode Control +#Stop-Service -Name YMC -Force +#Set-Service -Name YMC -StartupType Disabled + + +Function Remove-LenovoPnPDrivers { + param ( + [switch]$pnpTest + ) + + if ($pnpTest) { + Write-Output "[DEBUG] pnpTest switch is enabled" + } + else { + Write-Output "[DEBUG] pnpTest switch is NOT enabled" + } + + $pnputilOutput = pnputil /enum-drivers 2>&1 + + # Parse into driver blocks by detecting "Published Name:" as start of each + $driverBlocks = @() + $currentBlock = @() + + foreach ($line in $pnputilOutput) { + if ($line -match "^Published Name:\s+") { + if ($currentBlock.Count -gt 0) { + $driverBlocks += , ($currentBlock -join "`n") + $currentBlock = @() + } + } + $currentBlock += $line + } + + if ($currentBlock.Count -gt 0) { + $driverBlocks += , ($currentBlock -join "`n") + } + + $lenovoDrivers = @() + + foreach ($block in $driverBlocks) { + if ($pnpTest) { + #Write-Output "`n[DEBUG] Raw Driver Block:" + #Write-Output $block + } + + $publishedName = if ($block -match "Published Name:\s+(oem\d+\.inf)") { $matches[1] } else { $null } + $providerName = if ($block -match "Provider Name:\s+(.+)") { $matches[1].Trim() } else { $null } + + if ($publishedName -and $providerName -like "*Lenovo*") { + $lenovoDrivers += $publishedName + } + } + + if (-not $lenovoDrivers) { + Write-Output "No Lenovo drivers found." + return + } + + foreach ($inf in $lenovoDrivers) { + if ($pnpTest) { + Write-Output "Would remove: $inf" + } + else { + Write-Output "Removing: $inf" + #pnputil /delete-driver $inf /uninstall /force + } + } +} + + +Remove-LenovoPnPDrivers -pnpTest:$pnpTest + + +# Checks if ImControllerService exists, stops it if running, and disables startup. +Function Disable-ImControllerService { + $service = Get-Service -Name ImControllerService -ErrorAction SilentlyContinue + + if ($null -eq $service) { + Write-Host "ImControllerService not found on this system." + } + else { + if ($service.Status -eq "Running") { + Write-Host "ImControllerService is running. Stopping service..." + Stop-Service -Name ImControllerService -Force + } + + Write-Host "Disabling ImControllerService..." + Set-Service -Name ImControllerService -StartupType Disabled + Write-Host "ImControllerService has been stopped (if running) and disabled." + } +} + +# Example usage: +Disable-ImControllerService + + +#Debug-AppInfo "Dell Digital Delivery" + +if ($debug) { + Write-Output "***************** Debugging info *****************" + + Write-Output "`n==== Debug: All Uninstall Items (Wrapped Table) ====" + Get-ItemProperty ` + HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* ` + -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName } | + Sort-Object DisplayName | + Select-Object DisplayName, UninstallString, Publisher | + Format-Table -AutoSize -Wrap + + + Write-Output "`n==== List of User Apps (Appx) from System (-AllUsers) ====" + Get-AppxPackage -AllUsers | + Sort-Object -Property Name | + Format-Table Name, + @{Label = "Publisher"; Expression = { $_.Publisher.Substring(0, [Math]::Min(20, $_.Publisher.Length)) } } + + Write-Output "`n==== List of System Apps (Provisioned) ====" + Get-AppxProvisionedPackage -Online | + Sort-Object -Property DisplayName | + Format-Table DisplayName, + @{Label = "Publisher"; Expression = { $_.Publisher.Substring(0, [Math]::Min(20, $_.Publisher.Length)) } } +} diff --git a/scripts_wip/Win_DieMicrosoftCrapware v1.12.ps1 b/scripts_wip/Win_DieMicrosoftCrapware v1.12.ps1 new file mode 100644 index 00000000..eed7ae5a --- /dev/null +++ b/scripts_wip/Win_DieMicrosoftCrapware v1.12.ps1 @@ -0,0 +1,736 @@ +<# +NOTES + 1.0 10/23/2024 silversword411 initial version + 1.1 1/1/2025 silversword411 adding debug + 1.2 1/29/2025 silversword411 new Remove-App function to support array + 1.3 2/9/2025 silversword411 foldercreate and runasuser snippet + 1.4 2/9/2025 silversword411 adding DieMSAccountNags + 1.5 2/10/2025 Expand -debug section to list all software including registry-based, and updated Remove-M365 to handle wildcards + 1.6 2/17/2025 removing power automate + 1.7 5/7/2025 Added parameters to optionally leave Office, Teams, and OneDrive + 1.8 6/10/2025 Add Microsoft.Edge.GameAssist MicrosoftTeams Microsoft.ZuneVideo (Music & TV) + 1.9 8/5/2025 Start Experiences App + 1.10 11/19/2025 fixed onedrive removal + 1.11 12/16/2025 change leaveoffice to remove everything except en-us + 1.12 1/15/2026 – Fixed OneDrive removal when files are locked by Explorer by force-unloading OneDrive shell components, retrying deletion, and scheduling delete-on-reboot for stubborn per-user OneDrive binaries. + +#> + +param( + [switch]$debug, + [switch]$leaveoffice, + [switch]$leaveteams, + [switch]$leaveonedrive +) + +{ { foldercreate } } +{ { runasuser } } + +if ($debug) { + $DebugPreference = "Continue" +} +else { + $DebugPreference = "SilentlyContinue" + $ErrorActionPreference = 'silentlycontinue' +} + +Foldercreate -Paths "$env:ProgramData\TacticalRMM\temp" + +### Uninstall functions +Function Remove-App-MSI-QN([String]$appName) { + $appCheck = Get-ChildItem ` + -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall ` + | Get-ItemProperty ` + | Where-Object { $_.DisplayName -eq $appName } ` + | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling $($appCheck.DisplayName)" + $uninst = $appCheck.UninstallString + " /qn /norestart" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-EXE-SILENT([String]$appName) { + $appCheck = Get-ChildItem ` + -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall ` + | Get-ItemProperty ` + | Where-Object { $_.DisplayName -eq $appName } ` + | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling $($appCheck.DisplayName)" + $uninst = $appCheck.UninstallString + " -silent" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-MSI_EXE-Quiet([String]$appName) { + $appCheck = Get-ChildItem ` + -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall ` + | Get-ItemProperty ` + | Where-Object { $_.DisplayName -eq $appName } ` + | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling $($appCheck.DisplayName)" + $uninst = $appCheck.UninstallString[1] + " /qn /restart" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-MSI_EXE-S([String]$appName) { + $appCheck = Get-ChildItem ` + -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall ` + | Get-ItemProperty ` + | Where-Object { $_.DisplayName -eq $appName } ` + | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling $($appCheck.DisplayName)" + $uninst = $appCheck.UninstallString[1] + " /S" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-MSI-I-QN([String]$appName) { + $appCheck = Get-ChildItem ` + -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall ` + | Get-ItemProperty ` + | Where-Object { $_.DisplayName -eq $appName } ` + | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling $($appCheck.DisplayName)" + $uninst = $appCheck.UninstallString.Replace("/I", "/X") + " /qn /norestart" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App([String]$appName) { + $app = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like $appName } + if ($app) { + foreach ($package in $app) { + Write-Host "Uninstalling $($package.Name)" + Remove-AppxPackage -Package $package.PackageFullName -AllUsers + } + $provApp = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $appName } + if ($provApp) { + foreach ($proPackage in $provApp) { + Write-Host "Uninstalling provisioned $($proPackage.DisplayName)" + Remove-AppxProvisionedPackage -Online -PackageName $proPackage.PackageName -AllUsers + } + } + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-M365 { + param ( + [string]$appName + ) + + # Retrieve all matches (including 64-bit and 32-bit registry paths) + $matches = Get-ItemProperty ` + 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', + 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' ` + -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -like $appName } + + if (-not $matches) { + Write-Host "$appName is not installed on this computer" + return + } + + foreach ($m in $matches) { + if ($m.UninstallString) { + $uninstallString = $m.UninstallString + " DisplayLevel=False" + Write-Host "Uninstalling '$($m.DisplayName)' with command: $uninstallString" + cmd /c $uninstallString + } + else { + Write-Host "No uninstall string found for '$($m.DisplayName)'" + } + } +} + +Function Check-UninstallString([String]$appName) { + $appCheck = Get-ChildItem ` + -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall ` + | Get-ItemProperty ` + | Where-Object { $_.DisplayName -eq $appName } ` + | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "$($appCheck.DisplayName) $($appCheck.UninstallString)" + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +Function Remove-App-EXE-S-QUOTES([String]$appName) { + $appCheck = Get-ChildItem ` + -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall ` + | Get-ItemProperty ` + | Where-Object { $_.DisplayName -eq $appName } ` + | Select-Object -Property DisplayName, UninstallString + if ($appCheck -ne $null) { + Write-host "Uninstalling $($appCheck.DisplayName)" + $uninst = "`"" + $appCheck.UninstallString + "`"" + " /S" + cmd /c $uninst + } + else { + Write-Host "$appName is not installed on this computer" + } +} + +function Remove-OfficeC2RLanguagesExceptEnUS { + param( + [string]$KeepCulture = 'en-us' + ) + + $keep = $KeepCulture.ToLowerInvariant() + Write-Output "===== Office C2R language cleanup: keeping $keep, removing other cultures =====" + + $uninstallRoots = @( + 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', + 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' + ) + + $targets = Get-ItemProperty $uninstallRoots -ErrorAction SilentlyContinue | + Where-Object { + $_.DisplayName -match '^(Microsoft 365|Microsoft OneNote)\s-\s[a-z]{2}-[a-z]{2}$' -and + $_.UninstallString -match '(?i)OfficeClickToRun\.exe' + } + + if (-not $targets) { + Write-Output "No Office C2R language entries found to remove." + return + } + + foreach ($t in $targets) { + $name = $t.DisplayName + + # Culture from the DisplayName (most reliable in your case) + $culture = ([regex]::Match($name, '([a-z]{2}-[a-z]{2})$')).Value.ToLowerInvariant() + if (-not $culture) { continue } + + if ($culture -eq $keep) { + Write-Output "Keeping: $name" + continue + } + + # Parse: "C:\Path\OfficeClickToRun.exe" + $u = $t.UninstallString.Trim() + $m = [regex]::Match($u, '^\s*"(?[^"]+)"\s*(?.*)$') + if (-not $m.Success) { + Write-Output "Skipping (could not parse uninstall string): $name" + continue + } + + $exe = $m.Groups['exe'].Value + $args = $m.Groups['args'].Value + + if (-not (Test-Path $exe)) { + Write-Output "Skipping (OfficeClickToRun.exe not found): $exe" + continue + } + + # Add DisplayLevel=False if missing + if ($args -notmatch '(?i)\bDisplayLevel=') { + $args = "$args DisplayLevel=False" + } + + Write-Output "Removing: $name" + Write-Output "Start-Process `"$exe`" $args" + + try { + $p = Start-Process -FilePath $exe -ArgumentList $args -Wait -PassThru -WindowStyle Hidden + $exitcode = $p.ExitCode + Write-Output "ExitCode for $name : $exitcode" + } + catch { + Write-Output "FAILED removing $name : $($_.Exception.Message)" + } + } + + Write-Output "===== Office C2R language cleanup done. =====" +} + + + +# Remove built-in apps +Remove-App "*AmazonAlexa*" +Remove-App "*BubbleWitch3Saga*" +Remove-App "*CandyCrush*" +Remove-App "*Facebook*" +Remove-App "*Flipboard*" +Remove-App "*linkedin*" +Remove-App "*PandoraMediaInc*" +Remove-App "*Royal Revolt*" +Remove-App "*Spotify*" +Remove-App "*Sway*" +Remove-App "*Twitter*" +Remove-App "*xbox*" +Remove-App "4DF9E0F8.Netflix" +Remove-App "king.com.*" +Remove-App "Microsoft.BingFinance" +Remove-App "Microsoft.BingFoodAndDrink" +Remove-App "Microsoft.BingHealthAndFitness" +Remove-App "Microsoft.BingSearch" +Remove-App "Microsoft.BingSports" +Remove-App "Microsoft.BingTravel" +Remove-App "Microsoft.GamingApp" +Remove-App "Microsoft.GetHelp" +Remove-App "Microsoft.Getstarted" +Remove-App "Microsoft.Messaging" +Remove-App "Microsoft.MicrosoftOfficeHub" +Remove-App "Microsoft.Edge.GameAssist" +Remove-App "Microsoft.StartExperiencesApp" +Remove-App "Microsoft.ZuneVideo" +Remove-App "Microsoft.Edge.GameAssist" +Remove-App "Microsoft.MinecraftEducationEdition" +Remove-App "Microsoft.OneConnect" # Mobile Plans +Remove-App "Microsoft.OutlookForWindows" +Remove-App "Microsoft.Reader" +Remove-App "Microsoft.SkypeApp" +Remove-App "Microsoft.Wallet" +Remove-App "Microsoft.WindowsFeedbackHub" +Remove-App "Microsoft.WindowsReadingList" +Remove-App "Microsoft.Xbox.TCUI" +Remove-App "Microsoft.YourPhone" +Remove-App "microsoft.windowscommunicationsapps" +Remove-App "Microsoft.Copilot" +Remove-App "Microsoft.MicrosoftPowerBIForWindows" +Remove-App "Outlook (new)" +Remove-App "ZuneMusic" +Remove-App "Microsoft.BingNews" +Remove-App "Microsoft.BingWeather" +Remove-App "*PowerAutomate*" + + +function Remove-OneDriveCompletely { + <# + .SYNOPSIS + Removes Microsoft OneDrive as completely as practical in unattended/SYSTEM contexts. + + .DESCRIPTION + Handles common OneDrive install flavors: + - AppX (Microsoft.OneDriveSync / etc) and provisioned packages + - OneDriveSetup.exe /uninstall (System32 + SysWOW64) + - Per-user installs in %LocalAppData%\Microsoft\OneDrive for ALL profiles + - Program Files installs (x64/x86) + - ARP entries in HKLM + per-user entries under HKU + - Explorer namespace pin (optional but enabled by default here) + - Policies to block re-provisioning / reinstall (DisableFileSyncNGSC) + - Scheduled tasks and common Run keys that relaunch/reinstall + + Designed to be idempotent and safe to run repeatedly. + + .PARAMETER DisableReinstall + Writes policy to block OneDrive from running/reinstalling (recommended). + + .PARAMETER RemoveExplorerNamespace + Removes OneDrive from File Explorer navigation pane. + + .PARAMETER RemoveKnownScheduledTasks + Disables/removes common OneDrive scheduled tasks. + + .PARAMETER RemoveRunKeys + Removes Run key entries that auto-start OneDrive for all users. + + .PARAMETER Debug + Emits more verbose output. + + .NOTES + - Some changes may require Explorer restart or reboot to fully reflect in UI. + - If OneDrive is managed by M365/Intune, policy may re-apply. This function tries to enforce block locally. + #> + + param( + [switch]$DisableReinstall = $true, + [switch]$RemoveExplorerNamespace = $true, + [switch]$RemoveKnownScheduledTasks = $true, + [switch]$RemoveRunKeys = $true, + [switch]$Debug + ) + + $ea = if ($Debug) { "Continue" } else { "SilentlyContinue" } + $ErrorActionPreference = $ea + + function _Log([string]$msg) { Write-Output $msg } + + _Log "===== OneDrive removal starting (running as $([Environment]::UserName)) =====" + + # ------------------------------------------------------------------------- + # 0) Stop processes + # ------------------------------------------------------------------------- + _Log "Stopping OneDrive-related processes..." + Get-Process -Name "OneDrive*", "FileCoAuth", "Microsoft.SharePoint" -ErrorAction SilentlyContinue | + Stop-Process -Force -ErrorAction SilentlyContinue + + # ------------------------------------------------------------------------- + # 1) Remove AppX + provisioned + # ------------------------------------------------------------------------- + $appxPatterns = @( + "Microsoft.OneDriveSync", + "Microsoft.OneDrive", + "*OneDrive*" + ) + + foreach ($pat in $appxPatterns) { + $pkgs = Get-AppxPackage -AllUsers -ErrorAction SilentlyContinue | Where-Object { $_.Name -like $pat } + foreach ($p in $pkgs) { + _Log "Removing AppX: $($p.Name) ($($p.PackageFullName))" + try { Remove-AppxPackage -AllUsers -Package $p.PackageFullName -ErrorAction Stop } catch { _Log "FAILED AppX remove: $($_.Exception.Message)" } + } + + $prov = Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like $pat } + foreach ($pr in $prov) { + _Log "Removing provisioned AppX: $($pr.DisplayName) ($($pr.PackageName))" + try { Remove-AppxProvisionedPackage -Online -AllUsers -PackageName $pr.PackageName -ErrorAction Stop } catch { _Log "FAILED provisioned remove: $($_.Exception.Message)" } + } + } + + # ------------------------------------------------------------------------- + # 2) Run OneDriveSetup.exe /uninstall (covers system install) + # ------------------------------------------------------------------------- + $oneDriveSetupPaths = @( + "$env:SystemRoot\System32\OneDriveSetup.exe", + "$env:SystemRoot\SysWOW64\OneDriveSetup.exe" + ) + + foreach ($setup in $oneDriveSetupPaths) { + if (Test-Path $setup) { + _Log "Running uninstall: `"$setup`" /uninstall" + try { + $p = Start-Process -FilePath $setup -ArgumentList "/uninstall" -WindowStyle Hidden -Wait -PassThru -ErrorAction Stop + $exitcode = $p.ExitCode + _Log "Uninstall via $setup completed. ExitCode: $exitcode" + } + catch { + _Log "FAILED to run $setup /uninstall : $($_.Exception.Message)" + } + } + else { + _Log "OneDriveSetup not found at: $setup" + } + } + + # Stop again in case setup spawned anything briefly + Get-Process -Name "OneDrive*", "FileCoAuth" -ErrorAction SilentlyContinue | + Stop-Process -Force -ErrorAction SilentlyContinue + + # ------------------------------------------------------------------------- + # 3) Remove per-user program installs for ALL profiles (LocalAppData) + # ------------------------------------------------------------------------- + _Log "Removing per-user OneDrive binaries for all profiles..." + $userRoots = Get-ChildItem "C:\Users" -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.Name -notin @("Default", "Default User", "Public", "All Users") } + + foreach ($u in $userRoots) { + $localOD = Join-Path $u.FullName "AppData\Local\Microsoft\OneDrive" + $settingsOD = Join-Path $u.FullName "AppData\Local\Microsoft\OneDrive\settings" + if (Test-Path $localOD) { + _Log "Removing $localOD" + try { Remove-Item $localOD -Recurse -Force -ErrorAction Stop } catch { _Log "FAILED removing $localOD : $($_.Exception.Message)" } + } + + # Common leftover OneDrive folder (synced data) - only remove the folder itself, not the whole profile + $odFolder = Join-Path $u.FullName "OneDrive" + if (Test-Path $odFolder) { + _Log "Removing leftover OneDrive folder: $odFolder" + try { Remove-Item $odFolder -Recurse -Force -ErrorAction Stop } catch { _Log "FAILED removing $odFolder : $($_.Exception.Message)" } + } + + # Also check for "OneDrive - " folders + try { + Get-ChildItem -Path $u.FullName -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.Name -like "OneDrive -*" } | + ForEach-Object { + _Log "Removing leftover OneDrive folder: $($_.FullName)" + try { Remove-Item $_.FullName -Recurse -Force -ErrorAction Stop } catch { _Log "FAILED removing $($_.FullName) : $($_.Exception.Message)" } + } + } + catch {} + } + + # ------------------------------------------------------------------------- + # 4) Remove Program Files installs (x64/x86) + # ------------------------------------------------------------------------- + _Log "Removing OneDrive Win32 binaries (Program Files)..." + $programPaths = @( + "$env:ProgramFiles\Microsoft OneDrive", + "$env:ProgramFiles(x86)\Microsoft OneDrive", + "$env:ProgramData\Microsoft OneDrive" + ) | Where-Object { $_ -and $_.Trim() -ne "" } | Select-Object -Unique + + foreach ($path in $programPaths) { + if (Test-Path $path) { + _Log "Removing $path" + try { Remove-Item $path -Recurse -Force -ErrorAction Stop } catch { _Log "FAILED to remove $path : $($_.Exception.Message)" } + } + } + + # ------------------------------------------------------------------------- + # 5) Remove ARP entries (HKLM + HKU for all users) + # ------------------------------------------------------------------------- + _Log "Removing OneDrive uninstall registry entries (ARP)..." + + $uninstallRootsHKLM = @( + "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*", + "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" + ) + + $hklmEntries = Get-ItemProperty $uninstallRootsHKLM -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -eq "Microsoft OneDrive" -or $_.DisplayName -like "Microsoft OneDrive*" } + + foreach ($e in $hklmEntries) { + _Log "Deleting HKLM ARP entry: $($e.PSPath)" + try { Remove-Item $e.PSPath -Recurse -Force -ErrorAction Stop } catch { _Log "FAILED HKLM ARP delete: $($_.Exception.Message)" } + } + + # Per-user ARP (HKU) - catches Settings "Installed apps" entries not in HKLM + $hkuUninstall = "Registry::HKEY_USERS\*\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" + $hkuEntries = Get-ItemProperty $hkuUninstall -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -eq "Microsoft OneDrive" -or $_.DisplayName -like "Microsoft OneDrive*" } + + foreach ($e in $hkuEntries) { + _Log "Deleting HKU ARP entry: $($e.PSPath)" + try { Remove-Item $e.PSPath -Recurse -Force -ErrorAction Stop } catch { _Log "FAILED HKU ARP delete: $($_.Exception.Message)" } + } + + # ------------------------------------------------------------------------- + # 6) Remove Run keys (auto-start) + # ------------------------------------------------------------------------- + if ($RemoveRunKeys) { + _Log "Removing OneDrive Run key entries..." + $runPaths = @( + "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run", + "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run" + ) + + foreach ($rp in $runPaths) { + try { + $props = Get-ItemProperty -Path $rp -ErrorAction SilentlyContinue + if ($props.PSObject.Properties.Name -contains "OneDrive") { + _Log "Removing Run value OneDrive from $rp" + Remove-ItemProperty -Path $rp -Name "OneDrive" -ErrorAction SilentlyContinue + } + } + catch {} + } + + # Remove per-user Run keys for all loaded profiles + $hkuRun = "Registry::HKEY_USERS\*\Software\Microsoft\Windows\CurrentVersion\Run" + try { + Get-ChildItem "Registry::HKEY_USERS" -ErrorAction SilentlyContinue | ForEach-Object { + $p = "Registry::HKEY_USERS\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Run" + if (Test-Path $p) { + $props = Get-ItemProperty -Path $p -ErrorAction SilentlyContinue + if ($props.PSObject.Properties.Name -contains "OneDrive") { + _Log "Removing Run value OneDrive from $p" + Remove-ItemProperty -Path $p -Name "OneDrive" -ErrorAction SilentlyContinue + } + } + } + } + catch {} + } + + # ------------------------------------------------------------------------- + # 7) Scheduled tasks (common OneDrive tasks) + # ------------------------------------------------------------------------- + if ($RemoveKnownScheduledTasks) { + _Log "Disabling/removing common OneDrive scheduled tasks..." + $taskNameHints = @("OneDrive", "OneDrive Standalone Update Task", "OneDrive Reporting Task", "OneDrive Per-Machine Standalone Update Task") + try { + $tasks = Get-ScheduledTask -ErrorAction SilentlyContinue | Where-Object { + $n = $_.TaskName + $p = $_.TaskPath + ($n -match "OneDrive") -or ($p -match "OneDrive") + } + + foreach ($t in $tasks) { + _Log "Disabling task: $($t.TaskPath)$($t.TaskName)" + try { Disable-ScheduledTask -TaskName $t.TaskName -TaskPath $t.TaskPath -ErrorAction SilentlyContinue | Out-Null } catch {} + try { Unregister-ScheduledTask -TaskName $t.TaskName -TaskPath $t.TaskPath -Confirm:$false -ErrorAction SilentlyContinue | Out-Null } catch {} + } + } + catch {} + } + + # ------------------------------------------------------------------------- + # 8) Policy to block OneDrive from running/reinstalling + # ------------------------------------------------------------------------- + if ($DisableReinstall) { + _Log "Applying OneDrive block policy (DisableFileSyncNGSC=1)..." + try { + New-Item "HKLM:\Software\Policies\Microsoft\Windows\OneDrive" -Force | Out-Null + Set-ItemProperty "HKLM:\Software\Policies\Microsoft\Windows\OneDrive" ` + -Name "DisableFileSyncNGSC" -Type DWord -Value 1 -Force + } + catch { + _Log "FAILED setting OneDrive policy: $($_.Exception.Message)" + } + } + + # ------------------------------------------------------------------------- + # 9) Remove Explorer namespace (navigation pane) + # ------------------------------------------------------------------------- + if ($RemoveExplorerNamespace) { + _Log "Removing OneDrive Explorer namespace entry..." + $clsid = "{018D5C66-4533-4307-9B53-224DE2ED1FE6}" + $nsKeys = @( + "Registry::HKEY_CLASSES_ROOT\CLSID\$clsid", + "Registry::HKEY_CLASSES_ROOT\Wow6432Node\CLSID\$clsid" + ) + foreach ($k in $nsKeys) { + if (Test-Path $k) { + _Log "Deleting: $k" + try { Remove-Item $k -Recurse -Force -ErrorAction Stop } catch { _Log "FAILED deleting $k : $($_.Exception.Message)" } + } + } + } + + # ------------------------------------------------------------------------- + # 10) Final verification output (lightweight) + # ------------------------------------------------------------------------- + _Log "Verifying OneDrive presence..." + $odExeHits = @( + "$env:ProgramFiles\Microsoft OneDrive\OneDrive.exe", + "$env:ProgramFiles(x86)\Microsoft OneDrive\OneDrive.exe" + ) | Where-Object { $_ -and (Test-Path $_) } + + foreach ($h in $odExeHits) { _Log "STILL PRESENT: $h" } + + $arpHKLM = Get-ItemProperty $uninstallRootsHKLM -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -like "Microsoft OneDrive*" } | + Select-Object -First 5 + + if ($arpHKLM) { + _Log "STILL PRESENT in HKLM ARP (showing first 5):" + $arpHKLM | ForEach-Object { _Log " - $($_.DisplayName)" } + } + + $arpHKU = Get-ItemProperty $hkuUninstall -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -like "Microsoft OneDrive*" } | + Select-Object -First 5 + + if ($arpHKU) { + _Log "STILL PRESENT in HKU ARP (showing first 5):" + $arpHKU | ForEach-Object { _Log " - $($_.DisplayName) ($($_.PSPath))" } + } + + _Log "===== OneDrive removal completed. =====" +} + +# Usage inside your script: +if (-not $leaveonedrive) { Remove-OneDriveCompletely -DisableReinstall -RemoveExplorerNamespace -RemoveKnownScheduledTasks -RemoveRunKeys -Debug:$debug } + + +# Office-specific removal logic - only execute if not keeping Office +if (-not $leaveoffice) { + Remove-M365 "Microsoft 365*" + Remove-M365 "*OneNote*" +} +else { + Remove-OfficeC2RLanguagesExceptEnUS -KeepCulture 'en-us' +} + +# Teams-specific removal logic - only execute if not keeping Teams +if (-not $leaveteams) { + Remove-App "Microsoft.MicrosoftTeams" + Remove-App "MSTeams" + Remove-App "MicrosoftTeams" +} + +Invoke-AsCurrentUser -ScriptBlock { + + function Set-RegistryValue ($registryPath, $name, $value) { + $currentValue = (Get-ItemProperty -Path $registryPath -Name $name -ErrorAction SilentlyContinue).$name + if ($currentValue -ne $value) { + if (!(Test-Path -Path $registryPath)) { + New-Item -Path $registryPath -Force | Out-Null + } + Set-ItemProperty -Path $registryPath -Name $name -Value $value -Force + Write-Output "Set '$name' to $value at '$registryPath'" + } + else { + Write-Output "'$name' is already set to $value at '$registryPath'" + } + } + + # Registry settings + $registrySettings = @( + @{ + RegistryPath = "HKCU:\Software\Policies\Microsoft\Windows\CurrentVersion\AccountNotifications"; + Name = "DisableAccountNotifications"; + Value = 1 + }, + @{ + RegistryPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\UserProfileEngagement"; + Name = "ScoobeSystemSettingEnabled"; + Value = 0 + } + ) + + # Apply the registry settings + $registrySettings | ForEach-Object { + Set-RegistryValue -registryPath $_.RegistryPath -name $_.Name -value $_.Value + } + +} -CaptureOutput + + +if ($debug) { + Write-Output "***************** Debugging info *****************" + + Write-Output "`n==== Debug: All Uninstall Items (Wrapped Table) ====" + Get-ItemProperty ` + HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*, ` + HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* ` + -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName } | + Sort-Object DisplayName | + Select-Object DisplayName, UninstallString, Publisher | + Format-Table -AutoSize -Wrap + + + Write-Output "`n==== List of User Apps (Appx) from System (-AllUsers) ====" + Get-AppxPackage -AllUsers | + Sort-Object -Property Name | + Format-Table Name, + @{Label = "Publisher"; Expression = { $_.Publisher.Substring(0, [Math]::Min(20, $_.Publisher.Length)) } } + + Write-Output "`n==== List of System Apps (Provisioned) ====" + Get-AppxProvisionedPackage -Online | + Sort-Object -Property DisplayName | + Format-Table DisplayName, + @{Label = "Publisher"; Expression = { $_.Publisher.Substring(0, [Math]::Min(20, $_.Publisher.Length)) } } + + # Parameter status info in debug mode + Write-Output "`n==== Parameter Status ====" + Write-Output "Keep Office: $leaveoffice" + Write-Output "Keep Teams: $leaveteams" + Write-Output "Keep OneDrive: $leaveonedrive" +} \ No newline at end of file