locked
Removed default apps still appear in start menu as broken after deployment RRS feed

  • Question

  • Hi all,

    I am currently using MDT 2013 to deploy Windows 10 on several systems. In the task sequence is a custom task to remove the default Windows apps.

    All default apps are uninstalled after deployment, but the icons/names still appear in the start menu and seem to be broken. Clicking these apps does nothing and in most cases the icon image is blank.

    Is this a known issue and is there a solution?

    The custom task contains the following script:

    # ***************************************************************************
    #
    # File:      RemoveApps.ps1
    #
    # Version:   1.2
    #
    # Author:    Michael Niehaus
    #
    # Purpose:   Removes some or all of the in-box apps on Windows 8, Windows 8.1,
    #            or Windows 10 systems.  The script supports both offline and
    #            online removal.  By default it will remove all apps, but you can
    #            provide a separate RemoveApps.xml file with a list of apps that
    #            you want to instead remove.  If this file doesn't exist, the
    #            script will recreate one in the log or temp folder, so you can
    #            run the script once, grab the file, make whatever changes you
    #            want, then put the file alongside the script and it will remove
    #            only the apps you specified.
    #
    # Usage:     This script can be added into any MDT or ConfigMgr task sequences.
    #            It has a few dependencies:
    #              1.  For offline use in Windows PE, the .NET Framework,
    #                  PowerShell, DISM Cmdlets, and Storage cmdlets must be
    #                  included in the boot image.
    #              2.  Script execution must be enabled, e.g. "Set-ExecutionPolicy
    #                  Bypass".  This can be done via a separate task sequence
    #                  step if needed, see http://blogs.technet.com/mniehaus for
    #                  more information.
    #
    # ------------- DISCLAIMER -------------------------------------------------
    # This script code is provided as is with no guarantee or waranty concerning
    # the usability or impact on systems and may be used, distributed, and
    # modified in any way provided the parties agree and acknowledge the
    # Microsoft or Microsoft Partners have neither accountabilty or
    # responsibility for results produced by use of this script.
    #
    # Microsoft will not provide any support through any means.
    # ------------- DISCLAIMER -------------------------------------------------
    #
    # ***************************************************************************


    # ---------------------------------------------------------------------------
    # Initialization
    # ---------------------------------------------------------------------------

    if ($env:SYSTEMDRIVE -eq "X:")
    {
      $script:Offline = $true

      # Find Windows
      $drives = get-volume | ? {-not [String]::IsNullOrWhiteSpace($_.DriveLetter) } | ? {$_.DriveType -eq 'Fixed'} | ? {$_.DriveLetter -ne 'X'}
      $drives | ? { Test-Path "$($_.DriveLetter):\Windows\System32"} | % { $script:OfflinePath = "$($_.DriveLetter):\" }
      Write-Verbose "Eligible offline drive found: $script:OfflinePath"
    }
    else
    {
      Write-Verbose "Running in the full OS."
      $script:Offline = $false
    }


    # ---------------------------------------------------------------------------
    # Get-LogDir:  Return the location for logs and output files
    # ---------------------------------------------------------------------------

    function Get-LogDir
    {
      try
      {
        $ts = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Stop
        if ($ts.Value("LogPath") -ne "")
        {
          $logDir = $ts.Value("LogPath")
        }
        else
        {
          $logDir = $ts.Value("_SMSTSLogPath")
        }
      }
      catch
      {
        $logDir = $env:TEMP
      }
      return $logDir
    }

    # ---------------------------------------------------------------------------
    # Get-AppList:  Return the list of apps to be removed
    # ---------------------------------------------------------------------------

    function Get-AppList
    {
      begin
      {
        # Look for a config file.
        $configFile = "$PSScriptRoot\RemoveApps.xml"
        if (Test-Path -Path $configFile)
        {
          # Read the list
          Write-Verbose "Reading list of apps from $configFile"
          $list = Get-Content $configFile
        }
        else
        {
          # No list? Build one with all apps.
          Write-Verbose "Building list of provisioned apps"
          $list = @()
          if ($script:Offline)
          {
            Get-AppxProvisionedPackage -Path $script:OfflinePath | % { $list += $_.DisplayName }
          }
          else
          {
            Get-AppxProvisionedPackage -Online | % { $list += $_.DisplayName }
          }

          # Write the list to the log path
          $logDir = Get-LogDir
          $configFile = "$logDir\RemoveApps.xml"
          $list | Set-Content $configFile
          Write-Information "Wrote list of apps to $logDir\RemoveApps.xml, edit and place in the same folder as the script to use that list for future script executions"
        }

        Write-Information "Apps selected for removal: $list.Count"
      }

      process
      {
        $list
      }

    }

    # ---------------------------------------------------------------------------
    # Remove-App:  Remove the specified app (online or offline)
    # ---------------------------------------------------------------------------

    function Remove-App
    {
      [CmdletBinding()]
      param (
            [parameter(Mandatory=$true,ValueFromPipeline=$true)]
            [string] $appName
      )

      begin
      {
        # Determine offline or online
        if ($script:Offline)
        {
          $script:Provisioned = Get-AppxProvisionedPackage -Path $script:OfflinePath
        }
        else
        {
          $script:Provisioned = Get-AppxProvisionedPackage -Online
          $script:AppxPackages = Get-AppxPackage
        }
      }

      process
      {
        $app = $_

        # Remove the provisioned package
        Write-Information "Removing provisioned package $_"
        $current = $script:Provisioned | ? { $_.DisplayName -eq $app }
        if ($current)
        {
          if ($script:Offline)
          {
            $a = Remove-AppxProvisionedPackage -Path $script:OfflinePath -PackageName $current.PackageName
          }
          else
          {
            $a = Remove-AppxProvisionedPackage -Online -PackageName $current.PackageName
          }
        }
        else
        {
          Write-Warning "Unable to find provisioned package $_"
        }

        # If online, remove installed apps too
        if (-not $script:Offline)
        {
          Write-Information "Removing installed package $_"
          $current = $script:AppxPackages | ? {$_.Name -eq $app }
          if ($current)
          {
            $current | Remove-AppxPackage
          }
          else
          {
            Write-Warning "Unable to find installed app $_"
          }
        }

      }
    }


    # ---------------------------------------------------------------------------
    # Main logic
    # ---------------------------------------------------------------------------

    $logDir = Get-LogDir
    Start-Transcript "$logDir\RemoveApps.log"

    Get-AppList | Remove-App

    Stop-Transcript

    • Moved by Bill_Stewart Friday, August 12, 2016 1:56 PM Move to more appropriate forum
    Friday, August 12, 2016 12:24 PM

Answers

  • If you're seeing these broken links on the Administrator login, then that should be expected because you're applying the updated layout after the admin profile has been generated, but all new users would inherit the new layout.

    If this post is helpful please vote it as Helpful or click Mark for answer.

    • Marked as answer by Ty Glander Sunday, August 28, 2016 10:35 PM
    Friday, August 26, 2016 5:40 PM

All replies

  • Is this what you are using? https://blogs.technet.microsoft.com/mniehaus/2015/11/11/removing-windows-10-in-box-apps-during-a-task-sequence/

    Many questions such as where do I find logs and what logs are interesting are found in: MDT TechNet Forum - FAQ & Getting Started Guide Please take the time to read it. Also if you don't post logs your problem won't be easily solved.

    Friday, August 12, 2016 6:08 PM
  • Yes, I am using this method.
    Monday, August 15, 2016 6:43 AM
  • You should tale a look at the RemoveApps.log

    Many questions such as where do I find logs and what logs are interesting are found in: MDT TechNet Forum - FAQ & Getting Started Guide Please take the time to read it. Also if you don't post logs your problem won't be easily solved.

    Monday, August 15, 2016 4:40 PM
  • Are you importing an updated Start menu layout that no longer has the removed apps pinned to the start menu?

    If this post is helpful please vote it as Helpful or click Mark for answer.

    Monday, August 15, 2016 5:14 PM
  • I have set the start screen with the desired layout and copied the settings to the default user folder.
    Friday, August 26, 2016 10:17 AM
  • If you're seeing these broken links on the Administrator login, then that should be expected because you're applying the updated layout after the admin profile has been generated, but all new users would inherit the new layout.

    If this post is helpful please vote it as Helpful or click Mark for answer.

    • Marked as answer by Ty Glander Sunday, August 28, 2016 10:35 PM
    Friday, August 26, 2016 5:40 PM
  • My apologies on the lateness of this.  I saw the dead icon situation about a year ago, but didn't understand what was happening.  I still don't, but I do know why you might have dead icon's after running Michael's script.

    One thing to pay attention to when running Michael Niehaus' script is the point in time when the script is run.

    One of the things noticed is that if we run this script too soon after the unattended install of Win10 completes, then we end up with dead icons in the Start menu.

    We are logged in as the Administrator and running the scripts while Windows is running (online), but that is not the reason why the dead icons are occurring.

    The reason is that at the time that the script is run, the results of the Get-AppxProvisionedPackage differ from what apps are seen by the Remove-AppxPackage command.

    Michael's script creates a list of apps that will be removed.  It creates a list of apps from the Get-AppxProvisionedPackage command (see the Get-AppList function).  It then uses this info when running both the Remove-AppxProvisionedPackage and Remove-AppxPackage commands in the Remove-App function.

    Remove-AppxProvisionedPackage works fine since it uses the list that came from Get-AppxProvisionedPackage.

    Unfortunately, if you run this script too soon like I did after installing Win10 and reaching the desktop , the apps list that Remove-AppxPackage sees isn't fully populated for about 15 minutes after the desktop is reached. So the command that tells Remove-AppxPackage to remove the 3D-Builder app might fail, because it isn't aware of that app yet.

    You can see this yourself by doing an unattended install of Win10.  Once the desktop is reached, open a powershell command window.

    Run:  Get-AppxProvisionedPackage (and you'll see a full list of apps).

    Then run:  Get-AppxPackage (and you'll see that some things aren't in the list like the 3DBuilder app)

    Next wait about 20 minutes and run Get-AppxPackage again.  You should see its results become longer.  We noticed that after a while, the Get-AppxPackage list will become fully populated.

    But if you run the Michael's script before the Get-AppxPackage list is fully populated, you may end up removing the Provisioned package for an app, but not the package that is installed for the logged in user.  This results in dead icons on the Start menu.

    I wrote a script that gets the list of apps from Get-AppxProvisionedPackage and then checks against the apps that Get-AppxPackage sees.  The script loops and checks every 15 seconds.  Once all the apps seen from Get-AppxProvisionedPackage are seen in the results from Get-AppxPackage then the screen reports "Done!".  On 5 different systems, it took about 15 minutes for the Get-AppxPackage to fully populate and see all the apps that Get-AppxProvisionedPackage was aware of.

    Why this delay after the start of Windows?  I don't know yet.

    Here's my script that I ran to do the check after reaching the desktop during an unattended install of Win10.

    You can add a similar function to Michael's script that verifies that all apps that are going to be removed are seen by Get-AppxPackage before proceeding.

    #Check to see when all apps in the AppxProvisionedPackage have a matching entry in the list from AppxPackage.
    #  I used this script to get a feel for when are all apps available for removal.
    #  I found that some apps are not available for removal soon after installing Win10.
    #  They don't appear in the Get-AppxPackage list until about 15 minutes has passed.
    
    
    #Create the list of apps from AppxProvisionedPackage.
    $list = @()
    Get-AppxProvisionedPackage -Online | ForEach-Object { $list += $_.DisplayName }
    
    
    Write-Host "STARTING"
    Get-Date | Write-Host
    
    
    #Set the flag that indicates if the apps are ready.
    $ready = "no"
    
    #Begin the loop.  Continue as long as the apps are not ready.
    While ($ready -ne "yes") {
    
    	#Get the list of AppxPackage.
    	$AppxPackagesList = Get-AppxPackage
    
    	
    	#See if each app in the AppxProvisionedPackage output has an equal entry in the AppxPackage output.
    	
    	#Set the flag that indicates if the apps have a listing.
    	$fail = 0
    	
    	ForEach ($listItem in $list) {
    
    	$current = $AppxPackagesList | Where-Object {$_.Name -eq $listItem }
    
    	if ($current) {
    		#App has a match.
    	} else {
    		#App does not have a match.
    		#Set the flag to show that a match was not made.
    		$fail = 1
    	}
    	}
    
    	
    	If ($fail -eq 0) {
    		#If all apps have a match, the set ready = yes  so that the loop will end.
    		$ready = "yes"
    	} else {
    		Get-Date | Write-Host
    		Write-Host "Apps not ready yet."
    		#wait for a while before looping.
    		Start-Sleep -Seconds 15
    	}
    
    }
    
    Get-Date | Write-Host
    Write-Host "ALL APPS ARE READY!...exiting."
    Exit
    
    
    

    Wednesday, February 1, 2017 5:17 PM