2010-05-12 91 views
9

我认为我有一个答案,但我越玩它,我就越认为这是PowerShell的一个设计缺陷。拖放到PowerShell脚本

我想拖放(或使用发送到机构)来传递多个文件和/或文件夹作为一个阵列到Powershell的脚本。

测试脚本

#Test.ps1 
param ([string[]] $Paths, [string] $ExampleParameter) 
"Paths" 
$Paths 
"args" 
$args 

尝试#1

我创建了下面的命令行的快捷方式,并拖曳到它的一些文件。这些文件会作为单独的参数出现,首先在位置上与脚本参数匹配,其余部分放置在$ args数组中。

快捷方式尝试#1

powershell.exe -noprofile -noexit -file c:\Test.ps1 

包装脚本

我发现我可以用一个包装脚本做到这一点...

#TestWrapper.ps1 
& .\Test.ps1 -Paths $args 

快捷方式包装脚本

powershell.exe -noprofile -noexit -file c:\TestWrapper.ps1 

批处理文件包装脚本

和它的作品通过批处理文件包装脚本...

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%}" 

试图解答

基思·希尔的出色suggestion使用下面的快捷方式命令行,但它没有传递参数c orrectly。带有空格的路径在到达Test.ps1脚本时被拆分。

powershell.exe -noprofile -noexit -command "& {c:\test1.ps1 $args}" 

有没有人找到一种方法来做到这一点,没有额外的脚本?

+0

下面是一个替代的解决方案,尽管它会[需要适应的powershell](HTTP://mathematica.stackexchange。 com/a/78414/5615) – William 2015-03-28 01:18:43

+0

用于记录...如果脚本使用Powershell -File ScriptName.ps1运行,并且该脚本没有param块,则$ args变量将精确包含what创建一个文件路径数组。 – 2016-01-13 22:25:28

+0

这里是一个[bug报告](https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/20575477--bug-drag-and-drop-to-scripts-shortcuts-split-pat)你可以upvote在Powershell的UserVoice上。 – 2017-08-22 14:31:07

回答

0

我不知道为什么我没有想到这一点迟早...

的秘密这一切的时候,由于它是由可用,一直参数属性“ValueFromRemainingArguments”。

快捷

powershell.exe -noexit -file c:\Test.ps1 

Test.ps1

param (
    [Parameter(ValueFromRemainingArguments=$true)] 
    $Path 
) 

'Paths' 
$Path 
1

您的快捷方式改成这样试试吧:

powershell.exe -noprofile -noexit -command "& {c:\test1.ps1 $args}" 
+0

对不起,这是一个优雅的答案,但不幸的是,路径被任何空白区分开。我已经更新了这个问题以反映这种尝试。 – 2010-05-12 18:16:19

+0

不,$ args是我测试过的一个字符串[]。您可能看到的是,如果将字符串数组呈现为字符串,PowerShell将使用$ OFS的值来分隔数组中的每个条目。如果未设置$ OFS,则PowerShell将使用空格作为分隔符。在你的脚本中,尝试设置'$ OFS =',''。 – 2010-05-12 19:08:58

+0

是$ args是一个数组,但问题不是由数组扩展引起的。在快捷方式上拖动文件时,Windows会传递由空格分隔的路径,并在必要时用引号括起来。您的快捷方式第二次传递文件,这次没有引号。脚本收到的是一个很长的字符串,然后通过在任何空白处分割它来解析它。我喜欢你的想法,甚至试图将参数(@args)作为一个数组(@($ args))包裹起来,然后将$ OFS解决方案添加到命令行中,但无济于事。如果你尝试它,你会明白我的意思。 – 2010-05-12 21:27:45

1

我对Powershell Microsoft Connect网站提起了bug report

+1

微软已将Powershell臭虫报告从Connect连接到UserVoice,我无法再找到这个错误报告。我会尽快删除这个“答案”。如果有人想要打开一个错误报告,他们欢迎它... https://windowsserver.uservoice.com/forums/301869-powershell – 2016-01-13 22:33:54

+1

我重新打开一个那里,尽可能多的细节,但我看到由于过去7年没有做任何事情,我真的不期待任何事情。 https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/20575477--bug-drag-and-drop-to-scripts-shortcuts-split-pat – 2017-08-21 00:31:32

+0

谢谢,Amine Izumie,我已投了票它。有趣的是,现在Powershell是开源的,有更多时间的人可以提交一个解决这个问题的合并请求。 https://github.com/PowerShell/PowerShell – 2017-08-21 14:01:38

7

文件或文件夹传递到PowerShell脚本最简单的方法就是像一个包装脚本如下:

@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文件

副本

赋予其与脚本文件相同的名称,但带有扩展名。蝙蝠

例如“hello.ps1” < - >“hello.bat”

删除文件/文件夹到批处理文件,它将把它们传递给脚本。

一个示例脚本代码可能是这样的:

"hello world" 
$args 
$args.Gettype().Fullname 
+0

不是最简单的,但可能是微软修复我认为是错误的唯一方法。 – 2011-10-28 20:29:58

+1

是否有任何理由不使用单行'powershell.exe -NoExit -Command'&'%〜dpn0.ps1'%*“'而不是循环参数?它不处理包含空格的路径,但据我所知,上述批处理脚本也不是。 – billyjmc 2015-06-03 16:42:12

17

我意识到这个问题是几年老了,但由于它仍然有很多关于通过运行PowerShell的谷歌查询的顶部结果一个资源管理器的拖放我想我会发布我今天想到的,希望它可以帮助其他人。

我想将文件拖放到PowerShell(ps1)脚本上,并找不到任何好的解决方案(没有涉及到额外的脚本或快捷方式)。我开始在注册表中寻找文件伙伴,并且提出了一些似乎完美的工作。

首先,我们需要为.PS1文件添加一个DropHandler条目,以便Explorer知道PS1文件应该接受拖放操作。通过此注册表进行更改。您可能必须创建ShellEx和DropHandler子项。

HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\ShellEx\DropHandler\ 
(Default) = {60254CA5-953B-11CF-8C96-00AA00B8708C} 

此丢弃处理程序是Windows脚本宿主所使用的处理程序。这是我的第一选择,因为它支持长文件名。如果遇到空间问题或其他问题,可以尝试使用标准的Shell32可执行文件(.exe,.bat等)放置处理程序:{86C86720-42A0-1069-A2E8-08002B30309D}

通过简单地调用文件类型的默认动词(当您双击文件时会发生什么情况)(看作Shell键的(Default)值),这两个drop处理程序都可以工作。在PS1文件的情况下,这是打开。默认情况下,该动词在记事本中显示PowerShell脚本 - 不是很有帮助。

改变这种行为,通过修改PS1文件打开动词:

HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell\Open\Command\ 
(Default) = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoExit -File "%1" %* 

打开时,以及这将在PowerShell中运行该脚本传递给它的所有参数(丢弃的文件)。脚本完成后,我已将它设置为保持打开状态,但可以通过删除-NoExit选项来更改此设置。

就是这样。我还没有做过任何广泛的测试,但到目前为止它似乎工作得很好。我可以删除单个文件/文件夹以及组。参数列表中文件的顺序并不总是您所期望的(Explorer对命令选定文件的一个怪癖),但除此之外它看起来很理想。您还可以在Shell:Sendto中创建PS1文件的快捷方式,使您可以使用“发送至”菜单传递文件。

下面是REG文件格式方面的变化:

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\" %*" 

注:

  • 由于这些变化双击Explorer中的PS1文件将执行脚本的结果;要编辑而不是打开,您必须使用右键单击菜单。就像一个建议(可悲的是从痛苦的经历中学到的:),如果你的脚本采取了破坏性行动,你可能会考虑一个确认/健全检查警卫。

  • 通过拖放操作运行的脚本将有一个默认的起始工作目录C:\Windows\system32\。另一个原因要小心。

  • 请记住,除非您使用签名脚本,否则您将需要更改您的Execution Policy(Set-ExecutionPolicy)。

  • 如果您在Windows 10上调整了对.PS1文件的处理,则需要删除将覆盖默认处理的注册表项HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ps1\UserChoice

+0

干得好!那肯定会有诀窍。我一直在使用cmd.exe批处理文件存根脚本,并且可能会继续。因为我需要确保任何人都可以执行这些任务,而不需要他们调整PC的默认.PS1处理。 ...一岁和一年更保守。 – 2013-01-02 16:27:29

+2

+1这应该得到更多的赞扬 – nixda 2013-07-25 23:17:47

+1

在Windows 8+上,确保添加'Windows注册表编辑器版本5.00'作为.REG文件的第一行 – Benjamin 2015-10-30 10:06:21

0

不幸的是,$args将分裂的空间你的论点,从而对含有它们的文件名不正确工作。但是,如果没有外部包装脚本,您仍然可以在.ps1中处理$args!由于您在快捷方式(或选择“发送至”)上拖放的所有内容都将作为绝对路径的空间连接列表传递给脚本,因此可以使用正则表达式为所有绝对路径事件分析$args和管道它FOREACH:

$pattern = '([a-zA-Z]:\\(((?![<>:"/\\|?*]).)+((?<![ .])\\)?)*)(\s|$)' 

Select-String "$pattern" -input "$args" -AllMatches | Foreach {$_.matches} | ForEach-Object { 
    $path = "$($_.Groups.Groups[1].Value)" 
    # ... 
} 

其中每个$path是绝对文件图案由here采取恰好一个绝对路径(包括那些具有内部空间)

我用圆括号将第一组与实际路径相匹配,并在末尾添加了(\s|$)组,这是“空白或字符串末尾”,因为快捷参数将与单个空格连接; $需要与参数列表中的最后一个路径匹配相匹配。

+0

问题是Powershell如何分割掉文件(它们的路径字符串)在参数中,而不是将它们视为第一个参数的数组。如果你删除参数块,$ args变量将包含你期望的东西(除非你使用Keith Hill的命令解决方案),而不用正则表达式重新创建分割。试试这个...... TestScript.ps1:$ args快捷方式:Powershell -File TestScript.ps1 – 2016-01-13 22:21:43