Drag and Drop to a Powershell script
我以为我对此有一个答案,但是我越玩它,就越把它视为Powershell的设计缺陷。
我想拖放(或使用"发送至"机制)将多个文件和/或文件夹作为数组传递给Powershell脚本。
测试脚本
1 2 3 4 5 6 |
尝试#1
我使用以下命令行创建了快捷方式,并将一些文件拖到该快捷方式上。文件作为单独的参数遇到,这些参数首先在位置上与脚本参数匹配,其余部分放在$ args数组中。
尝试#1的捷径
1 | powershell.exe -noprofile -noexit -file c:\\Test.ps1 |
包装脚本
我发现我可以使用包装脚本来做到这一点...
1 2 |
包装脚本的快捷方式
1 | powershell.exe -noprofile -noexit -file c:\\TestWrapper.ps1 |
批处理文件包装脚本
它通过批处理文件包装脚本工作...
1 2 3 4 5 6 7 8 9 | REM TestWrapper.bat SET args='%1' :More SHIFT IF '%1' == '' GOTO Done SET args=%args%,'%1' GOTO More :Done Powershell.exe -noprofile -noexit -command"& {c:\\test.ps1 %args%}" |
尝试的答案
凯斯·希尔(Keith Hill)提出了使用以下快捷命令行的绝妙建议,但是它没有正确传递参数。带有空格的路径在到达Test.ps1脚本时被分开。
1 | powershell.exe -noprofile -noexit -command"& {c:\\test1.ps1 $args}" |
有没有人找到一种无需额外脚本就能做到这一点的方法?
我意识到这个问题已经有好几年了,但是由于它仍然是许多与通过Explorer拖放运行PowerShell有关的Google查询的最高结果,我认为我会在今天发布我的想法希望它能帮助别人。
我希望能够将文件拖放到PowerShell(ps1)脚本上,却找不到任何好的解决方案(没有多余的脚本或快捷方式的东西)。我开始在注册表中查看文件关联,然后想出了一些似乎可以正常工作的东西。
首先,我们需要为.PS1文件添加一个DropHandler条目,以便资源管理器知道PS1文件应接受拖放操作。使用此注册表更改来执行此操作。您可能必须创建ShellEx和DropHandler子项。
1 2 | HKEY_CLASSES_ROOT\\Microsoft.PowerShellScript.1\\ShellEx\\DropHandler\\ (Default) = {60254CA5-953B-11CF-8C96-00AA00B8708C} |
此删除处理程序是Windows脚本宿主使用的处理程序。这是我的首选,因为它支持长文件名。如果遇到空格或其他问题,可以尝试使用标准Shell32可执行文件(.exe,.bat等)放置处理程序:
这两个放置处理程序都可以通过简单地调用文件类型(称为Shell键的
通过修改PS1文件的"打开"动词来更改此行为:
1 2 | HKEY_CLASSES_ROOT\\Microsoft.PowerShellScript.1\\Shell\\Open\\Command\\ (Default) ="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" -NoExit -File"%1" %* |
打开后,它将在PowerShell中运行脚本,并将所有参数(删除的文件)传递给它。我将其设置为在脚本完成后保持打开状态,但是您可以通过删除
而已。我没有做任何广泛的测试,但是到目前为止,它似乎运行得很好。我可以删除单个文件/文件夹以及组。参数列表中文件的顺序并不总是您所期望的(资源管理器如何对选定文件进行排序的怪癖),但除此之外似乎很理想。您还可以在
这两个都是REG文件格式的变化:
1 2 3 4 5 6 7 | Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\\Microsoft.PowerShellScript.1\\ShellEx\\DropHandler] @="{60254CA5-953B-11CF-8C96-00AA00B8708C}" [HKEY_CLASSES_ROOT\\Microsoft.PowerShellScript.1\\Shell\\Open\\Command] @="\"C:\\\\Windows\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe\" -NoExit -File \"%1\" %*" |
笔记:
-
这些更改的结果是,在资源管理器中双击PS1文件将执行脚本。要进行编辑而不是打开,则必须使用右键菜单。就像一个建议(从痛苦的经验中吸取的教训:)一样,如果您的脚本执行了破坏性的操作,则可以考虑使用确认/健全性检查防护。
-
通过拖放操作运行的脚本将具有默认的开始工作目录
C:\\Windows\\system32\\ 。另一个要小心的理由。 -
请记住,除非使用签名脚本,否则您将需要更改执行策略(Set-ExecutionPolicy)。
-
如果您已调整Windows 10上.PS1文件的处理方式,则需要删除注册表项
HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\.ps1\\UserChoice ,它将覆盖默认处理方式。
将文件或文件夹传递到Powershell脚本的最简单方法是包装器脚本,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 | @echo off rem the name of the script is drive path name of the Parameter %0 rem (= the batch file) but with the extension".ps1" set PSScript=%~dpn0.ps1 set args=%1 :More shift if '%1'=='' goto Done set args=%args%, %1 goto More :Done powershell.exe -NoExit -Command"& '%PSScript%' '%args%'" |
您要做的就是
制作.bat文件的副本
为它提供与脚本文件相同的名称,但扩展名为.bat
例如" hello.ps1" <->" hello.bat"
将文件/文件夹拖放到批处理文件上,它将把它们传递给脚本。
示例脚本代码可能如下所示:
自此以来,一直以来的秘密一直是参数属性" ValueFromRemainingArguments"。
捷径
1 | powershell.exe -noexit -file c:\\Test.ps1 |
Test.ps1
1 2 3 4 5 6 7 8 | [CmdletBinding()] param ( [Parameter(ValueFromRemainingArguments=$true)] $Path ) 'Paths' $Path |
更改此快捷方式,然后尝试:
1 | powershell.exe -noprofile -noexit -command"& {c:\\test1.ps1 $args}" |
对于那些正在寻找快速好用的解决方案以将n单个文件拖放到需要字符串参数的Powershell脚本中的用户,可以将其用作快捷方式:
1 | powershell.exe -noprofile -noexit -command"& {.\\myscript.ps1 ($args -join ' ')}" |
如果您的文件路径具有多个连续的空格,它可能会中断,但这对我来说效果很好,因为我从未遇到过需要使用此技术的此类文件。
不幸的是,
由于您在快捷方式上拖放的所有内容(或选择"发送到"的内容)都将作为空格连接的绝对路径列表传递到脚本,因此可以使用regex和pipe解析所有出现的绝对路径的
1 2 3 4 5 6 | $pattern = '([a-zA-Z]:\\\\(((?![<>:"/\\\\|?*]).)+((?<![ .])\\\\)?)*)(\\s|$)' Select-String"$pattern" -input"$args" -AllMatches | Foreach {$_.matches} | ForEach-Object { $path ="$($_.Groups.Groups[1].Value)" # ... } |
其中每个
绝对文件模式是从这里获取的。
我将其包装在括号中(以使第一个组与实际路径匹配),并在末尾添加一个