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.
0 comments
Be the first to start the discussion.