Board logo

标题: [问题求助] PowerShell怎样复制 快捷方式 链接的源文件到剪贴板? [打印本页]

作者: g495326    时间: 2022-10-14 18:52     标题: PowerShell怎样复制 快捷方式 链接的源文件到剪贴板?

复制 快捷方式 链接的源文件或目录到剪贴板,以便于可以在别的文件夹中粘贴。
格式:脚本.ps1 任意多个快捷方式...
作者: went    时间: 2022-10-14 20:59

test.ps1
  1. $shell = New-Object -ComObject 'WScript.Shell' ; $arr = @()
  2. $args | foreach { $arr += $shell.CreateShortcut($_).TargetPath }
  3. $s = $arr -join "`r`n" ; Write-Host $s
  4. Set-Clipboard -Value $s
复制代码
powershell test.ps1 "C:\Users\Public\Desktop\腾讯QQ.lnk"  "F:\Desktop\微信.lnk"
作者: g495326    时间: 2022-10-14 23:20

回复 2# went


    好像不行,粘贴按钮仍然是灰色的

作者: went    时间: 2022-10-15 12:14

  1. [void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
  2. $shell = New-Object -ComObject 'WScript.Shell'
  3. $paths = New-Object 'System.Collections.Specialized.StringCollection'
  4. $args | foreach {
  5.     $file_str = $shell.CreateShortcut($_).TargetPath
  6.     Write-Host $file_str
  7.     [void]$paths.Add($file_str)
  8. }
  9. [System.Windows.Forms.Clipboard]::SetFileDropList($paths)
复制代码

作者: g495326    时间: 2022-10-15 15:02

回复 4# went


    多谢,如果能把该脚本加入到 快捷方式 的右键菜单,就更方便使用了
作者: went    时间: 2022-10-15 17:35

test.bat 管理员运行
  1. @echo off & cd /d "%~dp0"
  2. set "ps1=F:\Desktop\test.ps1"
  3. reg add "HKCR\lnkfile\shell\复制源到剪贴板\command" /ve /d "powershell \"%ps1%\" %%1" /f
  4. pause&exit
复制代码
F:\Desktop\test.ps1
只支持单个文件右键
作者: g495326    时间: 2022-10-15 19:03

回复 6# went


    多文件选择,我使用 发送到 菜单 -> 脚本.ps1解决了
    但框择多个文件时会夹杂着非lnk文件,这时脚本会报错。
    能改成对于传递进来的非lnk文件正常复制吗?即:脚本.ps1 1.lnk 2.txt 3.lnk
    复制1和3的源文件和2.txt到剪贴板
作者: went    时间: 2022-10-15 23:13

回复 7# g495326
  1. [void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
  2. $shell = New-Object -ComObject 'WScript.Shell'
  3. $paths = New-Object 'System.Collections.Specialized.StringCollection'
  4. $args | foreach {
  5.     if($_.EndsWith('.lnk')){
  6.         $file_str = $shell.CreateShortcut($_).TargetPath
  7.     } else {
  8.         $file_str = $_
  9.     }
  10.     Write-Host $file_str
  11.     [void]$paths.Add($file_str)
  12. }
  13. [System.Windows.Forms.Clipboard]::SetFileDropList($paths)
复制代码

作者: g495326    时间: 2022-10-16 08:52

回复 8# went


    多谢,但使用过程中,只要一个链接所指向的源文件不存在,复制会失败。因为粘贴时什么都不会发生。
    例如:1.lnk 链接 1.txt,2.lnk 链接 2.txt,3.lnk 链接 3.txt,此时我把1.txt删除。然后执行:脚本.ps1 1.lnk 2.lnk 3.lnk
    然后在另一文件夹中执行粘贴将会失败。此时正常的表现应该是跳过1.txt,仅复制2.txt和3.txt。

    另一个是当链接的源文件移动了位置,脚本获取链接的源文件位置仍是旧位置,也会造成复制的失败
    例如:1.lnk 链接 1.txt(假设为c:\1.txt),然后移动1.txt到新的位置(d:\1.txt)。
    然后执行:脚本.ps1 1.lnk,获取的源文件路径是c:\1.txt,而不是d:\1.txt

    还有一个是,能否在脚本运行时,检测到shift键按下且剪贴板中有文件内容,则把当前要复制的文件内容追加到剪贴板。(在右键菜单执行脚本)
    例如:2.lnk 链接 2.txt,此时先复制1.txt,按下shift键,然后执行:脚本.ps1 2.lnk,此时剪贴板应存在1.txt和2.txt
作者: went    时间: 2022-10-16 19:23

  1. using namespace 'Microsoft.PowerShell.Commands.AddType.AutoGeneratedTypes';cls
  2. [void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
  3. Add-Type -Name 'WinApi' -MemberDefinition '[DllImport("user32.dll")]public static extern short GetKeyState(uint VK);'
  4. $shell = New-Object -ComObject 'WScript.Shell'
  5. $paths = New-Object 'System.Collections.Specialized.StringCollection'
  6. if([WinApi]::GetKeyState(16) -band 0x8000){ $paths = [System.Windows.Forms.Clipboard]::GetFileDropList() }
  7. $args | foreach { [void]$paths.Add($shell.CreateShortcut($_).TargetPath) }
  8. $paths = $paths | Select-Object -Unique | Where-Object {[System.IO.File]::Exists($_)}
  9. [System.Windows.Forms.Clipboard]::SetFileDropList($paths)
  10. $paths
复制代码
回复 9# g495326
作者: g495326    时间: 2022-10-16 22:31

本帖最后由 g495326 于 2022-10-16 22:34 编辑

回复 10# went


    多谢。但还有些问题
    链接的源文件位置变化,运行报错
    链接的源文件是目录时,运行报错
    对于非lnk文件,运行报错
作者: went    时间: 2022-10-17 20:23

本帖最后由 went 于 2022-10-19 16:04 编辑
  1. using namespace 'Microsoft.PowerShell.Commands.AddType.AutoGeneratedTypes'
  2. using namespace 'System.Windows.Forms'
  3. using namespace 'System.Collections.Specialized';cls
  4. [void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
  5. Add-Type -Name 'WinApi' -MemberDefinition '[DllImport("user32.dll")]public static extern short GetKeyState(uint VK);'
  6. $shell = New-Object -ComObject 'WScript.Shell'
  7. $paths = New-Object 'StringCollection'
  8. $arr_err = New-Object 'System.Collections.ArrayList'
  9. if([WinApi]::GetKeyState(16) -band 0x8000){ write-host 'shift';$paths = [Clipboard]::GetFileDropList() }
  10. $args | foreach { [void]$paths.Add($_) }
  11. $paths = &{
  12. $paths | Select-Object -Unique | foreach {
  13. #目录
  14. if([System.IO.Directory]::Exists($_)){ return $_ }
  15. #文件
  16. if([System.IO.File]::Exists($_)){
  17. #lnk文件
  18. if($_.EndsWith('.lnk')){
  19. $p = $shell.CreateShortcut($_).TargetPath
  20. if([System.IO.File]::Exists($p)){ return $p }
  21. if([System.IO.Directory]::Exists($p)){ return $p }
  22.                 [void]$arr_err.Add(('{0} -> {1}' -f $_,$p))
  23. return $null
  24. }
  25. #其它文件
  26. return $_
  27. }
  28. } | Select-Object -Unique
  29. }
  30. if($paths.Count -gt 0){
  31. [Clipboard]::SetFileDropList($paths)
  32. 'ok'
  33. $paths
  34. '-----------'
  35. }
  36. if($arr_err.Count -gt 0){
  37. 'fail'
  38. $arr_err
  39. '-----------'
  40. pause
  41. }
复制代码

作者: g495326    时间: 2022-10-17 22:10

本帖最后由 g495326 于 2022-10-17 22:19 编辑

回复 12# went


    多谢,但还是有之前的问题1,2
    1、快捷方式 链接的 源文件被删除了,运行报错。这种情况应该跳过这些文件。最后打印出这些快捷方式的路径,并阻塞等待任意键之后结束(之所以阻塞,是因为右键菜单中执行,脚本执行完成后会自动关闭PS窗口)
    2、快捷方式 链接的 源文件 位置被改变,运行也会报错。比如 1.lnk 链接 1.txt,1.txt被移动到另一位置。脚本将无法获取1.txt的新位置
    3、shift的检测有时会检测不到,最后发现是脚本检测shift状态时,shift已被释放。能否脚本一运行就首先检测shift状态
作者: went    时间: 2022-10-18 13:04

源文件报错第28行改为
  1. if($paths.Count -gt 0){ [Clipboard]::SetFileDropList($paths) }
复制代码
检测shift要加载dll耗时,只有多按一点时间 5-8行都是
作者: g495326    时间: 2022-10-18 14:23

回复 14# went


    我的意思是,打印出链接失效的快捷方式的本身的路径,比如执行:脚本.ps1 1.lnk,1.lnk的源文件找不到,则打印1.lnk本身的路径并提示按任意键继续
    还有1.lnk 链接的源文件位置变化后,执行:脚本.ps1 1.lnk后,仍能找到新的源文件,而不是以找不到源文件处理。(记事本程序可以在处理这种情况,我想脚本也会有办法吧)
    论坛回复不及时,方便说下微信吗(可短消息回我)
作者: went    时间: 2022-10-18 20:12

回复 15# g495326


    21行 return $null 改为
  1. Write-Host ('未找到源 {0} -> {1}' -f $_,$p);pause
  2. return $null
复制代码

作者: g495326    时间: 2022-10-19 13:46

回复 16# went

不是每遇到一个找不到源文件,就暂停
而是把这些错误搜集起来,在脚本结束前一起显示
作者: went    时间: 2022-10-19 16:05

回复 17# g495326


    12楼改了,你直接复制
作者: g495326    时间: 2022-10-19 23:03

回复 18# went


    还是有之前提到的问题,源文件改名或移动位置,脚本无法获取新的位置,导致失败。而记事本可以。
   
作者: g495326    时间: 2022-10-21 18:53

回复 18# went


    在文件对话框中使用,闪退。能解决下吗?谢谢了

作者: went    时间: 2022-10-21 21:50

回复 20# g495326


   我win11,用不了发送到菜单
作者: g495326    时间: 2022-10-21 22:09

回复 21# went


    win11有发送到菜单啊,真的,帮帮忙吧!

作者: went    时间: 2022-10-21 22:42

win11

作者: g495326    时间: 2022-10-21 23:00

回复 23# went


    发送到 不支持文件的,可以创建快捷方式。C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file <脚本全路径>
作者: went    时间: 2022-10-21 23:23

回复 24# g495326


    对话框选择文件我测试是ok的


你在脚本最后添加一行 pause
看看是否有报错
作者: g495326    时间: 2022-10-22 11:59

本帖最后由 g495326 于 2022-10-22 12:01 编辑

回复 25# went


    加入pause后仍闪退,我怀疑是ps版本的问题,你版本多少
作者: g495326    时间: 2022-10-24 11:59

回复 25# went


    对于源文件改名的情况,我找到了两篇资料,你看一下
ShellLinkObject.Resolve 方法 (Shldisp.h) - Win32 apps | Microsoft Learn
https://learn.microsoft.com/zh-c ... redirectedfrom=MSDN

IShellLinkA::Resolve (shobjidl_core.h) - Win32 apps | Microsoft Learn
https://learn.microsoft.com/en-u ... ishelllinka-resolve
作者: went    时间: 2022-10-24 23:23

回复 27# g495326


    目标都变了不可能还能定位到
    上面的意思是lnk目标改变,还是能解析到lnk里原先保存的源目标,而不至于报错
作者: g495326    时间: 2022-10-25 22:41

回复 28# went


    对于源文件改名的问题,我找到了一个命令行程序,与脚本放在同一目录。
    能修改一下脚本,通过调用该程序获取源文件吗?获取到的路径仍需要判断存不存在。
   




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2