3

In Powershell, this command Get-AppxPackage *name* can show a package full details. Is it possible to use any Windows API to get that equivalent result?

I've seen this question and details of all Package Query APIs. But they all need full package names or a running package process handle. Those don't work with wildcard string.

For example, if I installed this package Microsoft.WindowsCalculator_8wekyb3d8bbwe I can get details with Get-AppxPackage *Calculator* command. It is possible with any Windows API? I want to avoid system() or CreateProcess() sort of things.

Biswapriyo
  • 3,491
  • 3
  • 22
  • 42

2 Answers2

2

Thanks to @f6a4 answer. I took a reverse way to accomplish my goal. Here are my procedure:

I find an answer to find the DLL behind Get-AppxPacage cmdlet in Powershell. With this command (Get-Command Get-AppxPackage).dll, Powershell shows the DLL file path as follows:

C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.Windows.Appx.PackageManager.Commands\v4.0_10.0.0.0__31bf3856ad364e35\Microsoft.Windows.Appx.PackageManager.Commands.dll

Go to that path in File Explorer and open Microsoft.Windows.Appx.PackageManager.Commands.dll file in any .NET decompiler. Here I used dnSpy. The Get-AppxManifest command section has this C# code:

protected override void ProcessRecord()
{
    AppxPackage appxPackage = this.packageManager.FindPackage(this.Package);
    if (appxPackage != null)
    {
        string str;
        if (appxPackage.IsBundle)
        {
            str = "\\AppxMetadata\\AppxBundleManifest.xml";
        }
        else
        {
            str = "\\AppxManifest.xml";
        }
        using (FileStream fileStream = new FileStream(appxPackage.InstallLocation + str, FileMode.Open, FileAccess.Read))
        {
            using (XmlReader xmlReader = XmlReader.Create(fileStream, new XmlReaderSettings
            {
                DtdProcessing = DtdProcessing.Ignore
            }))
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.Load(xmlReader);
                base.WriteObject(xmlDocument);
            }
        }
    }
}

I converted that code a similar C code with Windows API. Here is the code snippet:

ExpandEnvironmentStringsW(L"%ProgramFiles%\\WindowsApps", Buffer, MAX_PATH);

swprintf(FirstFile, MAX_PATH, L"%ls\\*", Buffer);

hFile = FindFirstFileW(FirstFile, &fileInfo);
if (hFile != INVALID_HANDLE_VALUE) {
    do {
        if (wcsstr(fileInfo.cFileName, AppxName) != 0) {
            memcpy(PackageName, fileInfo.cFileName, MAX_PATH);
        }
    } while (FindNextFileW(hFile, &fileInfo) != 0);
}
Biswapriyo
  • 3,491
  • 3
  • 22
  • 42
1

You could browse the app folder and grab the names from the xml manifest files. Admin rights are needed to get access to the app folder.

This example lists all apps with "xbox" in their name. The logic can be easily adapted to C# or another language.

$appNameFilter = '*xbox*'

[System.Collections.Generic.List[string]]$appList = @()

$apps = Get-ChildItem 'C:\Program Files\WindowsApps' -Recurse -Filter 'AppxManifest.xml'

foreach( $app in $apps ) {

    $xml     = [xml](Get-Content $app.FullName)
    $appName = $xml.Package.Properties.DisplayName

    if( $appName -like $appNameFilter -and !$appList.Contains( $appName )) {
        $appList.Add( $appName )
    }
}

$appList
f6a4
  • 1,684
  • 1
  • 10
  • 13