在 Windows 中,文件副檔名與可執行程式的關聯存儲於註冊表,但手動解析註冊表需處理 32/64 位重定向、用戶選擇覆蓋等複雜情況。更簡單且可靠的方式是直接呼叫 Shell32.dll 的 FindExecutable API,讓作業系統幫你完成關聯解析。本文示範如何在 PowerShell 中透過 C# 簽名呼叫該 API。
$Source = @"
using System;
using System.Text;
using System.Runtime.InteropServices;
public class Win32API
{
[DllImport("shell32.dll", EntryPoint = "FindExecutable", CharSet = CharSet.Auto)]
public static extern long FindExecutableA(string lpFile, string lpDirectory, StringBuilder lpResult);
public static string FindExecutable(string filePath)
{
var buffer = new StringBuilder(1024);
long result = FindExecutableA(filePath, string.Empty, buffer);
// 返回值 >= 32 表示成功
return result >= 32 ? buffer.ToString() : $"Error: ({result})";
}
}
"@
Add-Type -TypeDefinition $Source -ErrorAction SilentlyContinue
$file = "C:\Windows\windowsupdate.log"
$exe = [Win32API]::FindExecutable($file)
Write-Host "$file 將由 $exe 開啟"
輸出範例:
C:\Windows\windowsupdate.log 將由 C:\Windows\System32\notepad.exe 開啟
FindExecutable 需要實體文件,無法僅用副檔名查詢。.cer、.pfx 憑證文件由 MMC 管理,呼叫此 API 可能導致程式崩潰(社群回報)。若需「不依賴實體文件」查詢副檔名關聯,可解析 HKEY_CLASSES_ROOT\.ext → ProgID → shell\open\command,但需自行處理 32/64 位視圖與參數展開(%1 等)。
對於「已有文件,想知道雙擊會開啟什麼程式」的需求,FindExecutable 是最省力、最準確的方案。PowerShell 配合 Add-Type 內嵌 C# P/Invoke,幾行代碼即可調用原生 API,極大拓展了腳本能力。