October 13th, 2026
0 reactions

Is it MSIX? Part 3: Find Package and Application Identity with TASKLIST and PowerShell

Principal Software Engineer

We previously determined how to programmatically retrieve a packaged process’ package and application identity. Now let’s find MSIX package identity using existing tools.

TASKLIST.EXE

Using the packaged app AzVpnSysTrayApp.exe from our previous example, we know the “image name” (aka executable filename) and that its PID (process ID) is 7664.

TASKLIST.EXE /APPS lists packaged processes and their package names:

[C:] TASKLIST /APPS

Image Name                                              PID    Mem Usage Package Name
================================================== ======== ============ ==================================================
CalculatorApp.exe (App)                               82876    106,528 K Microsoft.WindowsCalculator_11.2508.4.0_x64__8weky
...

That’s overkill when we’re interested in a specific process. We can use the /FI (filter) option to limit the output to our target process:

[C:] TASKLIST /APPS /FI "PID eq 7664"

Image Name                                              PID    Mem Usage Package Name
================================================== ======== ============ ==================================================
AzVpnSysTrayApp.exe (App)                              7664     33,004 K Microsoft.AzureVpn_4.0.5.0_x64__8wekyb3d8bbwe

Or we can specify the image name and get the same result:

[C:] TASKLIST /APPS /FI "IMAGENAME eq AzVpnSysTrayApp.exe"

Image Name                                              PID    Mem Usage Package Name
================================================== ======== ============ ==================================================
AzVpnSysTrayApp.exe (App)                              7664     33,008 K Microsoft.AzureVpn_4.0.5.0_x64__8wekyb3d8bbwe

The Package Name column is actually the package full name.

Voila! Package identity for the packaged process.

Unfortunately, TASKLIST doesn’t display the Application User Model ID. For that, we need to get more creative.

Application Identity via PowerShell

Fortunately, it’s easy enough to call the package query APIs from PowerShell.

Save the following PowerShell script to Get-Identity.ps1:

Param(
    [Parameter(Mandatory=$true)]
    [int]$ProcessId
)

Set-StrictMode -Version 3.0

$ErrorActionPreference = "Stop"

# Define APIs via P/Invoke
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace AppModel
{
    public static class PackageUtil
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(
            int access,
            bool inherit,
            int processId);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool CloseHandle(IntPtr handle);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        public static extern int GetPackageFullName(
            IntPtr hProcess,
            ref int packageFullNameLength,
            StringBuilder packageFullName);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        public static extern int GetApplicationUserModelId(
            IntPtr hProcess,
            ref int applicationUserModelIdLength,
            StringBuilder applicationUserModelId);

        public const int PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;

        public const int APPMODEL_ERROR_NO_PACKAGE = 15700;
        public const int APPMODEL_ERROR_NO_APPLICATION = 15703;

        // PACKAGE_FULL_NAME_MAX_LENGTH does not include the null terminator
        public const int PACKAGE_FULL_NAME_MAX_LENGTH = 127;

        // APPLICATION_USER_MODEL_ID_MAX_LENGTH includes the null terminator
        public const int APPLICATION_USER_MODEL_ID_MAX_LENGTH = 130;
    }
}
"@

function Get-IdentityFromPid
{
    param(
        [Parameter(Mandatory=$true)]
        [int]$ProcessId
    )

    $handle = [AppModel.PackageUtil]::OpenProcess(
        [AppModel.PackageUtil]::PROCESS_QUERY_LIMITED_INFORMATION,
        $false,
        $ProcessId)

    if ($handle -eq [IntPtr]::Zero)
    {
        Write-Warning "Failed to open process $ProcessId"
        return
    }

    try
    {
        # PackageFullName max length is well defined and not large,
        # so preallocate the worst case.
        $length = [AppModel.PackageUtil]::PACKAGE_FULL_NAME_MAX_LENGTH + 1
        $packageFullName = New-Object System.Text.StringBuilder $length

        $rc = [AppModel.PackageUtil]::GetPackageFullName(
            $handle,
            [ref]$length,
            $packageFullName)

        if ($rc -eq [AppModel.PackageUtil]::APPMODEL_ERROR_NO_PACKAGE)
        {
            return [pscustomobject]@{
                PID = $ProcessId
                ImageName = (Get-Process -Id $ProcessId).ProcessName
                PackageFullName = $null
                ApplicationUserModelId = $null
            }
        }
        elseif ($rc -ne 0)
        {
            Write-Warning "Failed to retrieve package name for PID $ProcessId (error $rc)"
            return $null
        }

        $length = [AppModel.PackageUtil]::APPLICATION_USER_MODEL_ID_MAX_LENGTH
        $applicationUserModelId = New-Object System.Text.StringBuilder $length

        $rc = [AppModel.PackageUtil]::GetApplicationUserModelId(
            $handle,
            [ref]$length,
            $applicationUserModelId)

        if ($rc -eq [AppModel.PackageUtil]::APPMODEL_ERROR_NO_APPLICATION)
        {
            return [pscustomobject]@{
                PID = $ProcessId
                ImageName = (Get-Process -Id $ProcessId).ProcessName
                PackageFullName = $packageFullName.ToString()
                ApplicationUserModelId = $null
            }
        }
        elseif ($rc -ne 0)
        {
            Write-Warning "Failed to retrieve application identity for PID $ProcessId (error $rc)"
            return $null
        }

        return [pscustomobject]@{
            PID = $ProcessId
            ImageName = (Get-Process -Id $ProcessId).ProcessName
            PackageFullName = $packageFullName.ToString()
            ApplicationUserModelId = $applicationUserModelId.ToString()
        }
    }
    finally
    {
        [AppModel.PackageUtil]::CloseHandle($handle) | Out-Null
    }
}

Get-IdentityFromPid $ProcessId

Now run the script with a PID to display its package and application identity:

[C:] pwsh -c .\Get-Identity.ps1 7664

 PID ImageName       PackageFullName                               ApplicationUserModelId
 --- ---------       ---------------                               ----------------------
7664 AzVpnSysTrayApp Microsoft.AzureVpn_4.0.5.0_x64__8wekyb3d8bbwe Microsoft.AzureVpn_8wekyb3d8bbwe!App

With TASKLIST and PowerShell, we can find MSIX package identity and its Application User Model ID without writing a native application.

Voila! Package and application identity, as requested.

Author

Howard Kapustein
Principal Software Engineer

MSIX Development Engineer/Architect

0 comments