如何在PowerShell中获取支持Unicode与长路径的快捷方式目标?
读取含长路径/Unicode字符的.lnk快捷方式目标路径的解决方案
现有方法的局限性
方法1:WScript.Shell COM对象
原采纳答案的代码:
$Shell = New-Object -ComObject WScript.Shell $Target = $Shell.CreateShortcut('<full-path-to-shortcut>').TargetPath
存在的问题:
- 快捷方式文件路径过长时,无法读取该文件
- 目标路径包含中日韩等Unicode字符时,返回结果会变成
??? - 快捷方式路径本身包含Unicode字符时,无法创建快捷方式对象
方法2:Win32_ShortcutFile WMI类
获赞较少的替代方案代码:
$Path = '<full-path-to-shortcut>' -replace "\\", "\\\\" $ShortcutFile = Get-WmiObject Win32_ShortcutFile -Filter "name = '$Path'" $Target = $ShortcutFile.Target
存在的问题:
- 不支持网络UNC路径(如
\\Server\Share\Shortcut.lnk) - 不支持带UNC限定符的路径(如
\\?\UNC\Server\Share\Shortcut.lnk)
可行解决方案
方案1:直接解析.lnk二进制结构
.lnk文件有固定二进制格式,通过读取二进制内容提取目标路径,完全支持长路径和Unicode:
function Get-ShortcutTarget { param( [Parameter(Mandatory=$true)] [string]$ShortcutPath ) # 处理长路径,添加\\?\前缀绕过260字符限制 if (-not $ShortcutPath.StartsWith("\\?\")) { if ($ShortcutPath.StartsWith("\\")) { $ShortcutPath = "\\?\UNC\" + $ShortcutPath.Substring(2) } else { $ShortcutPath = "\\?\" + $ShortcutPath } } $bytes = [System.IO.File]::ReadAllBytes($ShortcutPath) $targetOffset = [System.BitConverter]::ToUInt32($bytes, 0x14) $targetLength = [System.BitConverter]::ToUInt16($bytes, 0x1C) $targetBytes = $bytes[($targetOffset + 0x4C)..($targetOffset + 0x4C + $targetLength - 1)] $targetPath = [System.Text.UnicodeEncoding]::Unicode.GetString($targetBytes) # 还原长路径格式 if ($targetPath.StartsWith("\\")) { $targetPath = "\\?\UNC\" + $targetPath.Substring(2) } else { $targetPath = "\\?\" + $targetPath } return $targetPath } # 使用示例 Get-ShortcutTarget -ShortcutPath "C:\长路径测试\包含Unicode字符的快捷方式.lnk"
说明:
- 借助
\\?\长路径前缀突破Windows传统路径长度限制 - 直接读取.lnk二进制内容提取Unicode编码的目标路径,完美兼容中日韩等字符
- 支持本地长路径、UNC网络路径
方案2:调用系统原生API
通过调用shell32.dll的SHGetShortcutTargetWAPI,配合长路径前缀实现需求:
Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; public class ShortcutHelper { [DllImport("shell32.dll", CharSet = CharSet.Unicode)] private static extern int SHGetShortcutTargetW(IntPtr hWnd, string pszShortcut, IntPtr pszTarget, ref int cchTarget); public static string GetShortcutTarget(string shortcutPath) { int bufferSize = 2048; IntPtr targetBuffer = Marshal.AllocHGlobal(bufferSize * 2); try { int result = SHGetShortcutTargetW(IntPtr.Zero, shortcutPath, targetBuffer, ref bufferSize); if (result == 0) { return Marshal.PtrToStringUni(targetBuffer); } else { throw new System.ComponentModel.Win32Exception(result); } } finally { Marshal.FreeHGlobal(targetBuffer); } } } "@ function Get-LnkTarget { param( [Parameter(Mandatory=$true)] [string]$Path ) # 处理长路径 if (-not $Path.StartsWith("\\?\")) { $Path = $Path -replace "^\\\\", "\\?\UNC\" if (-not $Path.StartsWith("\\?\")) { $Path = "\\?\" + $Path } } return [ShortcutHelper]::GetShortcutTarget($Path) } # 使用示例 Get-LnkTarget -Path "\\Server\Share\超长路径\Unicode快捷方式.lnk"
说明:
- 调用系统原生API,兼容性更强
- 同样依赖
\\?\前缀处理长路径 - 部分受限环境下可能需要管理员权限
验证说明
即使系统已启用长路径支持,WScript.Shell的CreateShortcut方法仍会截断目标路径(最长仅246字符),而上述两种方案可以完整提取超长路径的目标内容,同时完美支持Unicode字符。
内容的提问来源于stack exchange,提问作者Tanaka Saito
相关产品推荐
相关产品推荐

