含Emoji路径的快捷方式(.lnk)目标复制失败问题排查
问题描述
我需要编写一个PowerShell脚本,功能如下:
- 接受一个必选参数:快捷方式(.lnk)文件的完整路径
- 解析快捷方式指向的目标项(文件或目录)
- 将目标项复制到脚本当前工作目录
测试时发现异常情况:当快捷方式的目标路径包含Emoji字符(例如C:\Movies\• Unidentified\[🇪🇸]\Amor, curiosidad, prozak y dudas (2001)\File.mkv),无论是使用Copy-Item cmdlet还是Shell.NameSpace + Folder.CopyHere()方法,脚本都不报错但完全不执行复制操作;路径不含Emoji时则运行正常。
我的系统默认编码为Windows-1252,怀疑是编码问题,尝试过设置UTF-8编码(代码如下)但没有改善:
[Text.Encoding] $encoding = [Text.Encoding]::UTF8 [console]::InputEncoding = $encoding [console]::OutputEncoding = $encoding $OutputEncoding = $encoding $PSDefaultParameterValues['Out-File:Encoding'] = $encoding $PSDefaultParameterValues['*:Encoding'] = $encoding
原脚本代码:
# Takes 1 mandatory argument pointing to a shortcut (.lnk) file, # resolves the shortcut's target item (a file or directory), # and copies that target item to the specified destination folder # using Windows default IFileOperation progress UI. param ( [Parameter( Position=0, Mandatory, ValueFromPipeline, HelpMessage="Enter the full path to a shortcut (.lnk) file.") ] [string] $linkFile = "", [Parameter( Position=1, ValueFromPipeline, HelpMessage="Enter the full path to the destination folder.") ] [string] $destinationFolder = $(Get-Location) ) $wsShell = New-Object -ComObject WScript.Shell $shellApp = New-Object -ComObject Shell.Application $targetItem = $wsShell.CreateShortcut($linkFile).TargetPath Write-Host [i] Link File..: ($linkFile) Write-Host [i] Target Item: ($targetItem) Write-Host [i] Destination: ($destinationFolder) Write-Host [i] Copying target item to destination folder... $shellApp.NameSpace("$destinationFolder").CopyHere("$targetItem") Write-Host [i] Copy operation completed. Exit(0)
问题原因
问题出在WScript.Shell的CreateShortcut方法上:该方法无法正确处理包含Unicode补充平面字符的路径(比如示例中的🇪🇸属于区域标志符号,是双码点Unicode字符),会导致获取到的TargetPath出现截断或编码错误,最终得到的路径是无效的。后续复制操作找不到对应的文件/目录,因此不执行任何操作。
而你尝试设置的控制台编码仅影响PowerShell的输入输出显示,无法解决COM对象内部解析路径时的编码问题。
解决方案
改用Shell.Application对象来解析快捷方式,它能正确处理全范围的Unicode字符。修改后的脚本如下:
# 解析快捷方式目标并复制到指定目录(支持含Emoji的路径) param ( [Parameter( Position=0, Mandatory, ValueFromPipeline, HelpMessage="输入快捷方式(.lnk)文件的完整路径。") ] [string] $linkFile = "", [Parameter( Position=1, ValueFromPipeline, HelpMessage="输入目标文件夹的完整路径。") ] [string] $destinationFolder = $(Get-Location) ) $shellApp = New-Object -ComObject Shell.Application # 用Shell.Application解析快捷方式,获取正确的目标路径 $shortcutParentFolder = $shellApp.NameSpace((Split-Path -Path $linkFile -Parent)) $shortcutItem = $shortcutParentFolder.ParseName((Split-Path -Path $linkFile -Leaf)) $targetItem = $shortcutItem.GetLink.Target.Path Write-Host [i] 快捷方式路径: $linkFile Write-Host [i] 目标项路径: $targetItem Write-Host [i] 目标文件夹: $destinationFolder Write-Host [i] 正在复制目标项到指定目录... # 执行复制(显示系统默认进度UI) $shellApp.NameSpace($destinationFolder).CopyHere($targetItem) Write-Host [i] 复制操作完成。 Exit(0)
关键修改说明:
- 移除
WScript.Shell的使用,改用Shell.Application的Namespace和ParseName方法定位快捷方式文件 - 通过
GetLink.Target.Path获取快捷方式的目标路径,该方法能正确解析包含Emoji等Unicode补充平面字符的路径 - 后续的
CopyHere操作使用正确的目标路径,即可正常执行复制
额外说明:
如果需要使用Copy-Item cmdlet执行复制,只需将复制部分替换为:
Copy-Item -Path $targetItem -Destination $destinationFolder -Recurse -Force
同样能正确处理含Emoji的路径。
内容的提问来源于stack exchange,提问作者ElektroStudios
相关产品推荐
相关产品推荐

