1709 How to remove ALL not-yet-installed apps with powershell?

Discussion in 'Windows 10' started by Olliw, Dec 17, 2017.

  1. Olliw

    Olliw MDL Member

    Mar 17, 2010
    191
    186
    10
    Hi!

    I'm trying to remove preprovisioned, not yet installed, apps / packages. I'm talking specifically about:
    - 'Adobe Photoshop Express'
    - 'Duolingo'
    - 'Eclipse Manager'
    - 'Network Speed Test'
    - 'News'
    - 'Power BI'
    - 'Sway'

    These apps are lurking in the start menu, but are not installed before a user actually clicks them.
    They are not detected by 'Get-AppxProvisionedPackage -Online' or 'Get-AppxPackage',
    Code:
    [String[]] $Query = 'Adobe*Photoshop*Express','Duolingo','Eclipse*Manager','Network*Speed*Test','News','Power*BI','Sway'
    Foreach ($Index in $Query) {
        Get-AppxProvisionedPackage -Online | Select PackageName, InstallLocation | Where PackageName -Like "*$index*"
        Get-AppxPackage -AllUsers -Name '*' | Select Name, InstallLocation | Where Name -Like "*$index*"
    }
    
    and therefore I can't uninstall them with powershell. They are not listed as installed apps either.
    - Are these preprovisioned packages? If not, what are they?
    - Are there any powershell command to remove these, or their start menu shortcuts?
     
  2. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    534
    926
    30
    That's because they're not App Packages, but Start Menu tiles that are populated by the content delivery system.

    They can be disabled via the registry and disabling the content delivery manager in its entirety, or by using a LayoutModification.xml custom Start Menu layout
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  3. Olliw

    Olliw MDL Member

    Mar 17, 2010
    191
    186
    10
    By 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content\DisableWindowsConsumerFeatures' = 1?
    I've tried that, but it does not remove them.

    "or by using a LayoutModification.xml custom Start Menu layout"
    Will that still allow users to modify start menu? I've read that customizing w10 start menu by xml mods locks it down.


    Edit: Are these relevant?
    - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager
    - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager\SuggestedApps
     
  4. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    534
    926
    30
    You can modify GPO to disable customizing of the start menu after a custom layout is applied, but simply adding the XML does not lock the Start Menu down. Preventing users from changing the Start Menu has to be done through Group Policy. Automatic locking of a custom layout is only done if it's being issued from a network server as the default Start Menu layout.

    And yes, that registry key is where you would disable various ContentDeliveryManager properties:

    "FeatureManagementEnabled" -Value 0
    "OemPreInstalledAppsEnabled" -Value 0
    "PreInstalledAppsEnabled" -Value 0
    "SilentInstalledAppsEnabled" -Value 0
    "SoftLandingEnabled" -Value 0
    "SystemPaneSuggestionsEnabled" -Value 0
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  5. dhjohns

    dhjohns MDL Guru

    Sep 5, 2013
    3,262
    1,731
    120
    Hmmm, interesting. How do you remove something that is not there?
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  6. crypticus

    crypticus MDL Senior Member

    Jun 29, 2015
    317
    142
    10
    They are just icons that leads to tricking download&install. so if you disable or delete icons. its done.
     
  7. Olliw

    Olliw MDL Member

    Mar 17, 2010
    191
    186
    10
    #7 Olliw, Dec 18, 2017
    Last edited: Dec 19, 2017
    (OP)
    Thanks. I have the reg values figured out now. Do you have an example of a LayoutModification.xml where suggested apps are removed?
    I'll take a look at it later when I have time. Heres a code snippet for setting reg values (if others need it)
    Code:
    #region Settings
        # ReadOnly true means the script won't change ANYTHING, only search for apps and registry values
        [Bool] $ReadOnly = $true
        [Bool] $DebugWinTemp = $false
        [Bool] $DebugConsole = $true
        If ($DebugWinTemp) {[String] $Global:DebugStr = [String]::Empty}
        [String] $WhatToConfig = 'Remove bloatware'
    #endregion Settings
    
    
    #region Functions
        #region Write-Output
        Function Out {
            param(
                [Parameter(Mandatory=$true, Position=0)]
                [String] $In
            )
            If ($DebugConsole) {
                Write-Output -InputObject $In
            }
            If ($DebugWinTemp) {
                $Global:DebugStr += $In + "`r`n"
            }
        }
        #endregion Write-Output
    
    #region Create reg dir
        Function Check-RegistryDir {
            Param(
                [Parameter(Mandatory=$true, Position=0)]
                [String] $Dir
            )
            If (!(Test-Path $Dir)) {
                    Out -In '   Reg dir does not exist, trying to create.'
                    If(!($ReadOnly)) {
                        $null = New-Item -ItemType Directory -Force -Path $Dir 2>&1
                        If (!($?)) {
                            Out -In '      ERROR: Dir could not be created'
                        }
                        Else {
                            Out -In '      SUCCESS: Dir was created'
                        }
                    }
                    Else {Out -In '      ReadOnly mode'}
                } 
            Else {
                Out -In '   Reg dir does already exist.'
            } 
        }
        #endregion Create reg dir
    
        #region Write registry dword
        Function Write-RegistryValueDword {
            Param(
                [Parameter(Mandatory=$true, Position=0)]
                [String] $Dir,
    
                [Parameter(Mandatory=$true, Position=0)]
                [String] $Key,
    
                [Parameter(Mandatory=$true, Position=0)]
                [Int] $Val
            )
            Out -In ('Dir: ' + $Dir + ' | Key: ' + $Key + ' | Val: ' + $Val)
            # Check if path exists, create if doesn't
            Check-RegistryDir $Dir
            # Continue only if Dir exists or gets created successfully
            If (Test-Path $Dir) {
                # Check if key exists
                $Exists = Get-ItemProperty -Path ('{0}' -f $Dir) -Name ('{0}' -f $Key) -ErrorAction SilentlyContinue
                # If key does not exist
                If (!($Exists)) {
                    Out -In '   Key does not exist. Creating key and setting value'
                    If (!($ReadOnly)) {
                        $null = Set-ItemProperty -Path $Dir -Name $Key -Value $Val 2>&1                       
                    }
                }
                # If key does exist   
                Else {
                    # Don't write new value if new key is the same
                    If ($Exists.$Key -eq $Val) {
                        Out -In '   Key does exist, and value is the same as the new one'
                    }
                    # Write new key if key is not the same
                    Else {
                        Out -In '   Key does exist, but is not equal to the new one. Trying to change it'
                        If (!($ReadOnly)) {
                            $null = Set-ItemProperty -Path $Dir -Name $Key -Value $Val 2>&1                 
                        }
                    }
                }       
                # Final check
                If ($ReadOnly) {
                    Out -In '      ReadOnly mode, succeeded in checking reg value'
                    }
                    Else {
                    $Exists = Get-ItemProperty -Path ('{0}' -f $Dir) -Name ('{0}' -f $Key) -ErrorAction SilentlyContinue
                    If ($Exists) {
                        If ($Exists.$Key -eq $Val) {
                        Out -In '      SUCCESS: Key is correct'}
                        Else {Out -In '      ERROR: Key does exist | Val was not set'}
                    }
                    Else {Out -In '      ERROR: Key does not Exist | Val was not set'}
                }
            }
        }
        #endregion Write registry dword
    #endregion Functions
    
    
    
    #region Set Registry values
        #region Prevent "Suggested Applications" from returning
        Out ("`r`n`r`n" + '### Prevent apps from returning')
        [String] $RegPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content'
        [String] $RegName = 'DisableWindowsConsumerFeatures'
        [Int]   $RegValue = 1
        Write-RegistryValueDword -Dir $RegPath -Key $RegName -Val $RegValue
        #endregion Prevent "Suggested Applications" from returning
    
        #region Disable suggestions on start menu
        Out ("`r`n" + '### Disable and remove suggested apps')
        [String]   $RegPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager'
        $RegValues = @(
            [PSCustomObject]@{Key = [String]'FeatureManagementEnabled'; Val = [Int]0}
            [PSCustomObject]@{Key = [String]'OemPreInstalledAppsEnabled'; Val = [Int]0}
            [PSCustomObject]@{Key = [String]'PreInstalledAppsEnabled'; Val = [Int]0}
            [PSCustomObject]@{Key = [String]'SilentInstalledAppsEnabled'; Val = [Int]0}
            [PSCustomObject]@{Key = [String]'SoftLandingEnabled'; Val = [Int]0}
            [PSCustomObject]@{Key = [String]'SystemPaneSuggestionsEnabled'; Val = [Int]0}
        )
        Foreach ($x in $RegValues) {
            Write-RegistryValueDword -Dir $RegPath -Key $x.Key -Val $x.Val
        }
        #endregion Disable suggestions on start menu
    #endregion Set Registry Values
    
    
    
    #region Debug
    If ($DebugWinTemp) {
        If ([String]::IsNullOrEmpty($DebugStr)) {
            $DebugStr = 'Everything failed'
        }
    
        # Write Output
        $DebugPath = 'C:\Windows\Temp\'
        $CurDate = Get-Date -Uformat "%y%m%d"
        $CurTime = Get-Date -Format "HHmmss"
        $DebugFileName = ('Debug Powershell ' + $WhatToConfig + ' ' + $CurDate + $CurTime + '.txt')
    
        $DebugStr | Out-File -FilePath ($DebugPath + $DebugFileName) -Encoding 'utf8'
        If (!($?)) {
            $DebugStr | Out-File -FilePath ($env:TEMP + '\' + $DebugFileName) -Encoding 'utf8'
        }
    }
    #endregion Debug
    
     
  8. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    534
    926
    30
    You can do what was recommended above with the default layout as your template, or use "Get-StartApps > $HOME\Desktop\StartApps.txt" and then use the AppIDs for the apps you want to display to populate your LayoutModification.xml
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  9. Olliw

    Olliw MDL Member

    Mar 17, 2010
    191
    186
    10
    #10 Olliw, Dec 22, 2017
    Last edited: Dec 22, 2017
    (OP)
    Can you apply it to a already created profile? If you can: How? I tried writing it to the same path as DefaulLayouts.xml and rebooted, that obviously did not do the trick..

    Edit: Import-StartLayout maybe. More testing later.
     
  10. Grywald

    Grywald MDL Novice

    Jun 25, 2014
    17
    3
    0
    Code:
    Reg Add "HKLM\WIM_Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages\Microsoft-Windows-ContentDeliveryManager-Package~31bf3856ad364e35~amd64~~10.0.16299.15" /v "Visibility" /t REG_DWORD /d 1 /f >> D:\ReportAboutW10.txt
    Reg Delete "HKLM\WIM_Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages\Microsoft-Windows-ContentDeliveryManager-Package~31bf3856ad364e35~amd64~~10.0.16299.15\Owners" /f >> D:\ReportAboutW10.txt
    Reg Unload HKLM\WIM_Software
    Dism /Image:D:\IsoWindows10 /Remove-Package /Packagename:Microsoft-Windows-ContentDeliveryManager-Package~31bf3856ad364e35~amd64~~10.0.16299.15
    No I don't know (how many Package ? Which PackageName ? etc) but I'm wonder it won't be good enough and better with dism instead ?
    From my point of view, PowerShell is to avoid (too many failures to remove ProvisionedAppxPackages) and I just rather a clean iso.