Get-ReparsePointAppInfo.psm1
<#PSScriptInfo
.SYNOPSIS Extracts and decodes information from App Execution Aliases reparse points. .VERSION 1.0 .GUID 1ba0d4e4-a6d8-4cda-8372-ee2de24302fd .AUTHOR asklar .COMPANYNAME .COPYRIGHT .TAGS .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .PRIVATEDATA .DESCRIPTION This script parses MSIX app execution aliases and extracts application information including package family name, AUMID, and executable path. .PARAMETER Path Path to the reparse point file to analyze. .EXAMPLE Get-ReparsePointAppInfo -Path "C:\Users\Foo\Bar.exe" .NOTES Author: Alexander Sklar Version: 1.0 Date: May 7, 2025 Requires: Windows PowerShell 5.1 or later #> function Get-ReparsePointAppInfo { param ( [Parameter(Mandatory = $true)] [string]$Path ) # Run the fsutil command and capture output $output = & fsutil reparsepoint query $Path # Initialize variables $tagValue = "" $tagName = "" $dataLength = "" $hexBytes = New-Object System.Collections.Generic.List[byte] $currentSection = "" # Process the output line by line foreach ($line in $output) { if ($line -match "Reparse Tag Value\s*:\s*(.*)") { $tagValue = $matches[1].Trim() } elseif ($line -match "Tag value:\s*(.*)") { $tagName = $matches[1].Trim() } elseif ($line -match "Reparse Data Length:\s*(.*)") { $dataLength = $matches[1].Trim() } elseif ($line -match "Reparse Data:") { $currentSection = "reparseData" } elseif ($currentSection -eq "reparseData" -and $line -match "^\s*[0-9a-fA-F]+:\s+(.*)") { # Extract the hex data, ignoring the offset at the beginning $hexData = $matches[1].Trim() # Split by spaces to get individual hex values $values = $hexData -split "\s+" # Convert each hex value to a byte and add to our list foreach ($value in $values) { if ($value -match "^[0-9a-fA-F]{2}$") { $hexBytes.Add([Convert]::ToByte($value, 16)) } } } } # Extract the 4-byte version value from the beginning $version = 0 if ($hexBytes.Count -ge 4) { $version = [BitConverter]::ToInt32($hexBytes.ToArray(), 0) } # Check if the version indicates multi-app support (value 3) $hasMultiAppSupport = ($version -eq 3) # Process the byte array to extract UTF-16 strings $decodedStrings = @() $currentBytes = New-Object System.Collections.Generic.List[byte] # Start after the 4-byte version (index 4) for ($i = 4; $i -lt $hexBytes.Count; $i += 2) { if ($i + 1 -ge $hexBytes.Count) { break } # Get the current two bytes (UTF-16 character) $byte1 = $hexBytes[$i] $byte2 = $hexBytes[$i + 1] # If we have a null character (0x0000), end the current string if ($byte1 -eq 0 -and $byte2 -eq 0) { if ($currentBytes.Count -gt 0) { $stringBytes = $currentBytes.ToArray() $string = [System.Text.Encoding]::Unicode.GetString($stringBytes) if ($string.Length -gt 0) { $decodedStrings += $string } $currentBytes.Clear() } } else { # Add bytes to the current string $currentBytes.Add($byte1) $currentBytes.Add($byte2) } } # Add the last string if there are remaining bytes if ($currentBytes.Count -gt 0) { $stringBytes = $currentBytes.ToArray() $string = [System.Text.Encoding]::Unicode.GetString($stringBytes) if ($string.Length -gt 0) { $decodedStrings += $string } } # Map decoded strings to specific categories $packageFamilyName = "" $aumid = "" $executablePath = "" $appType = "" # Parse the decoded strings based on the corrected mapping if ($decodedStrings.Count -ge 1) { $packageFamilyName = $decodedStrings[0] # First string is the package family name } if ($decodedStrings.Count -ge 2) { $aumid = $decodedStrings[1] # Second string is the AUMID } if ($decodedStrings.Count -ge 3) { $executablePath = $decodedStrings[2] # Third string is the executable path } if ($decodedStrings.Count -ge 4) { $appType = $decodedStrings[3] # Fourth string is the app type } # Return the object with the parsed information return [PSCustomObject]@{ Path = $Path ReparseTagValue = $tagValue TagName = $tagName DataLength = $dataLength Version = $version MultiAppSupport = $hasMultiAppSupport PackageFamilyName = $packageFamilyName AUMID = $aumid ExecutablePath = $executablePath AppType = $appType } } Export-ModuleMember -Function Get-ReparsePointAppInfo |