Microsoft Store UWP Apps – Removing Vulnerable Apps using Intune Remediations and Powershell

What are UWP (Appx) apps 

Universal Windows Platform (UWP) Appx packages are a modern application package format designed by Microsoft for its Windows 10 operating system and beyond. These packages allow developers to create platform-agnostic applications, meaning they can run seamlessly across a wide range of Windows-based devices, including PCs, tablets, smartphones, and the Xbox. The Appx packaging format encapsulates the application’s code, resources, assets, and metadata into a single package, simplifying installation, distribution, and management. It supports advanced features like adaptive user interfaces, which adjust to different screen sizes, and deep integration with Windows capabilities such as Cortana and live tiles. UWP Appx packages offer enhanced security through sandboxing, ensuring applications are isolated from each other and the system, thereby reducing the risk of malicious software affecting the device. This format is central to the Microsoft Store, where users can safely discover, install, and update UWP apps.

Are they installed per user or machine? 

When an app is installed by any user on a Windows system, core components of the app are stored in C:\Program Files\WindowsApps\ (which is a restricted folder) while user-specific components are installed in the user profile under C:\Users\[UserName]\AppData\Local\Packages\

Taking the new Teams client as an example, when the app is installed via the Microsoft Store or manually via Powershell, the app core components are stored under C:\Program Files\WindowsApps\MicrosoftTeams_23306.3309.2530.1346_x64__8wekyb3d8bbwe

While the user-specific components are installed under C:\Users\<username>\AppData\Local\Packages\MicrosoftTeams_8wekyb3d8bbwe

How do they get updated?

In an uncontrolled environment  – user can set App updates to “On” via Microsoft Store

 

In a controlled environment where Microsoft Store might be blocked for users, Auto update can be set via Intune or GPO

So no app should go out-of-date – right?

That’s partially true! providing auto-update is configured, the app will always be up-to-date for the logged-on user.

If a user had logged on to the machine previously and got Store Apps provisioned to themselves, those apps will never get updated unless the user logs back in. 

Let’s consider the following scenario, an admin had to remote in to solve a problem for a user, this creates a local profile for that admin with built-in apps automatically provisioned. Due to the nature of those apps, the core components will be installed system-wide under C:\Program Files\WindowsApps\ as explained previously.

If that admin never logs in again, the apps provisioned to them will soon go outdated. Even when an update is triggered for that app by the logged-on user, the old version will continue to be installed side-by-side with the new version. 

So what’s the big deal? Why is this a problem?

This only becomes a problem when an older version of an App becomes vulnerable and starts to get picked up by vulnerability scans. 

Manually going around and removing these vulnerable apps is a pain and is not scalable. 

Powershell to the rescue!

To solve this on a scalable basis, I have written a Powershell detection and remediation script that can be pushed to endpoints using Intune Remediations 

The scripts can be found on my Github repo

 

How does it work?

Both detection and remediation scripts should run in the SYSTEM context

The detection script

The detection script is designed to identify and address vulnerabilities in specific Universal Windows Platform (UWP) applications on a Windows device. It operates by defining a list of known vulnerable apps in the $VulnerableApps array. Each entry in this array includes the app’s name, a ‘fixed’ version number that is considered secure, and a de-provision status indicating whether the app should be entirely removed from the device.

The script then scans the device for each listed app, checking if any installed version is older (and hence more vulnerable) than the specified fixed version. It does this by using the get-appxpackage -AllUsers command, which fetches details of the specified app installed across all user accounts on the device. If it finds any app versions that are older than the fixed version, it adds them to a list of vulnerable apps found.

The primary focus of the script is to detect these vulnerable app versions and compile a comprehensive list of them. Once it identifies any vulnerable versions, the script can then trigger a remediation script (handled by a separate script or system) to either update these apps to the secure version or de-provision them entirely based on the specified criteria in the $VulnerableApps array. This makes the script a crucial part of a security protocol in a managed IT environment, helping maintain the integrity and safety of the application ecosystem on Windows devices.

The remediation script

The script works by iterating through this list of vulnerable apps. For each app, it checks the system to see if any installed versions are older than the specified secure version. If older, vulnerable versions are found, the script further checks if the secure version is already installed.

If a secure version is not present, and the app is not marked for de-provisioning, the script attempts to update the app using the Update-AppxStoreApp function – this is a modified version of the function that was written by David Machaj. This function triggers updates for Windows Store apps, ensuring they are upgraded to the non-vulnerable versions.

For apps marked for de-provisioning, or if updates are not successful, the script proceeds to remove the vulnerable versions from all user profiles on the device. This includes deleting the app package and its associated folder within the Program Files\WindowsApps directory.

Additionally, the script handles exceptions and outputs detailed information about its operations, including which apps are removed or updated, and any errors encountered during the process. This output is logged for review and auditing purposes.

The script is versatile and robust, designed to be run as a device script in Intune, providing an automated solution to ensure that only secure, up-to-date UWP applications are running on Windows devices in a managed IT environment.

In both Detection and Remediation Scripts, modify the contents of the following array to target specific packages – make sure the array contents match in both scripts.

 

Example output in Intune 

On some occasions, certain apps will continue to report as “installed” for the system user. This usually resolves itself when the machine is restarted

Microsoft Store UWP Apps – Removing Vulnerable Apps using Intune Remediations and Powershell
Tagged on:                 

7 thoughts on “Microsoft Store UWP Apps – Removing Vulnerable Apps using Intune Remediations and Powershell

  • February 29, 2024 at 6:55 pm
    Permalink

    This script seems to work exactly as stated, thank you! I’ve been wondering how to clear the noise from these findings for a while now.

    Now on to the next issue… How to deal with old Microsoft Teams findings related to users never logging into MS Teams to force the “auto-update” on their profile. Why couldn’t it just be left at the system level to manage…. Per-user profile installs are the worst.

    Reply
    • March 1, 2024 at 8:44 am
      Permalink

      Hi Brad, glad you found the script useful! Don’t have enough details but I take it you are referring to classic Teams (win32 app). If Teams is not used at all in your org, In this case, I would write a script to check for the exe version under %Appdata% for each profile on the endpoint, and if it’s older than certain version, delete it. Scenarios and resolution may vary depending on specific details.

      Reply
      • March 1, 2024 at 3:14 pm
        Permalink

        Ah! Yes, in my case we use the MS Teams “Machine-Wide installer”. From my testing, it seems that if you delete the files and someone down the road you deleted them for actually needs to utilize Teams down the road, it isn’t seamless for them reinstall due to the registry keys etc…

        My initial attempt at this worked successfully taking a two-step process. Uninstalling the older 1.4.x Teams system-side installer, upgrading it to the latest 1.6 (1.7 now) and then running a script that would load the NTUSER.DAT files, remove the HKCU uninstall registry keys for Teams to reinstall automatically if the user logs back in with the latest version.

        However, what I found is that the script would work great in testing using a normal domain account with administrative rights both locally and through remote PSSession, but when utilized through our deployment mechanism the “SYSTEM” account seemed to struggle with this type of task. Not sure if you have come across this or not.

        Not sure how this will show up in the chat, but here is the code below I was testing for reference in-case anyone else was interested. The code looks through each profile at the HKCU “Uninstall Key” specifically for Microsoft Teams with versions less than 1.6.00.20074. If found, it will delete the uninstall registry key removing the Add/Remove programs entry and also pull the install location (users profile) and delete the folder containing the binaries.

        If the user logs in again, the latest version would automatically be installed as the system-wide installer would be updated on the system. Would likely still be something that would be required to run anytime a new Teams vulnerability is patched. Unfortunately, with it not being usable at scale from early testing, I’ve hit a brick wall with remediating this finding.

        To note, these issues would only be found for users that actually never login to Teams since Teams will auto-update if you actually login to the app.

        #Product Name to Find
        $ProductName = “Microsoft Teams”
        #Specific version to find less than
        $DisplayVersion = “1.6.00.20074”

        # Regex pattern for SIDs
        $PatternSID = ‘S-1-5-21-\d+-\d+\-\d+\-\d+$’

        # Get Username, SID, and location of ntuser.dat for all users
        $ProfileList = gp ‘HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*’ | Where-Object {$_.PSChildName -match $PatternSID} |
        Select @{name=”SID”;expression={$_.PSChildName}},
        @{name=”UserHive”;expression={“$($_.ProfileImagePath)\ntuser.dat”}},
        @{name=”Username”;expression={$_.ProfileImagePath -replace ‘^(.*[\\\/])’, ”}}

        # Get all user SIDs found in HKEY_USERS (ntuser.dat files that are loaded)
        $LoadedHives = gci Registry::HKEY_USERS | ? {$_.PSChildname -match $PatternSID} | Select @{name=”SID”;expression={$_.PSChildName}}

        # Get all users that are not currently logged
        $UnloadedHives = Compare-Object $ProfileList.SID $LoadedHives.SID | Select @{name=”SID”;expression={$_.InputObject}}, UserHive, Username

        # Loop through each profile on the machine
        $RegistryKeys = @()

        Foreach ($item in $ProfileList) {
        # Load User ntuser.dat if it’s not already loaded
        IF ($item.SID -in $UnloadedHives.SID) {
        reg load HKU\$($Item.SID) $($Item.UserHive) | Out-Null
        }

        #####################################################################
        # This is where you can read/modify a users portion of the registry

        # This example deletes the Profiles key under Software\Microsoft\Office\16.0\Outlook for each user registry hive
        #Get-ChildItem registry::HKEY_USERS\$($Item.SID)\Software\Microsoft\Office\16.0\Outlook -Recurse | ForEach-Object {if ($_ -match “Profiles”){Remove-Item -Path “Registry::$_” -recurse -force -confirm:$false}}
        $RegistryKeys += Get-ChildItem registry::HKEY_USERS\$($Item.SID)\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall -Recurse

        #####################################################################

        # Unload ntuser.dat
        if($item.SID -in $UnloadedHives.SID) {
        ### Garbage collection and closing of ntuser.dat ###
        [gc]::Collect()
        reg unload HKU\$($Item.SID) | Out-Null
        }
        }

        $Findings = @()
        $FoldersToDelete = @()

        #Combine and verify version of installation to remove installed registry key and installation directory
        Foreach ($RegistryKey in $RegistryKeys){
        $NameOfKeys = $RegistryKey.GetValue(‘DisplayName’)
        $InstalledVersion = $RegistryKey.GetValue(‘DisplayVersion’)
        If($NameOfKeys -eq $ProductName -and $InstalledVersion -lt $DisplayVersion) {
        $Findings += $RegistryKey.Name
        $InstallFolderLocation = $RegistryKey.GetValue(‘InstallLocation’)
        $FoldersToDelete += $InstallFolderLocation
        }
        }

        #Remove installation Key from users registry (Removes Add/Remove Program Entry) – Remove -Whatif statement to execute
        Foreach ($Finding in $Findings){
        Remove-Item -Path “Registry::$Finding” -recurse -force -confirm:$false -ErrorAction SilentlyContinue -Whatif
        }

        #Remove installation folder of where media is – Remove -Whatif statement to execute
        Foreach ($FolderToDelete in $FoldersToDelete){
        Remove-Item -Path “$FolderToDelete” -recurse -force -confirm:$false -ErrorAction SilentlyContinue -WhatIf
        }

  • March 20, 2024 at 2:10 pm
    Permalink

    Great script, I been working on something similar and ran into your script which works great.
    I have a question, I added Microsoft.DesktopAppInstaller to the array and it’s detected, but when I run the remediation script I keep getting “failed with error 0x80070032” when trying to remove it for all profiles. Do you know why this might be with this particular app? When I’ve tested before manually I get similar error or the user is not logged in. The only way I have been able to uninstall the old version is to remove the old profiles that have it.

    Reply
    • March 20, 2024 at 4:03 pm
      Permalink

      Hey, glad you found it useful! Not sure about the specifics and it looks like you have done enough troubleshooting around it. Is th behaviour consistent when it comes to DesktopAppInstaller? Any specific user type that is not getting removed (Admin/standard)? Is deprovisioning the app all together an option?

      Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from Amir Sayes

Subscribe now to keep reading and get access to the full archive.

Continue reading