拖放到Powershell脚本

Nat*_*ley 15 powershell

我以为我对此有了答案,但是我玩的越多,我就越认为它是Powershell的设计缺陷.

我想拖放(或使用Send-To机制)将多个文件和/或文件夹作为数组传递给Powershell脚本.

测试脚本

#Test.ps1
param ( [string[]] $Paths, [string] $ExampleParameter )
"Paths"
$Paths
"args"
$args
Run Code Online (Sandbox Code Playgroud)

尝试#1

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

尝试#1的快捷方式

powershell.exe -noprofile -noexit -file c:\Test.ps1
Run Code Online (Sandbox Code Playgroud)

包装脚本

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

#TestWrapper.ps1
& .\Test.ps1 -Paths $args
Run Code Online (Sandbox Code Playgroud)

包装脚本的快捷方式

powershell.exe -noprofile -noexit -file c:\TestWrapper.ps1
Run Code Online (Sandbox Code Playgroud)

批处理文件包装器脚本

它通过批处理文件包装脚本工作...

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%}"
Run Code Online (Sandbox Code Playgroud)

尝试回答

Keith Hill提出了使用以下快捷命令行的优秀建议,但它没有正确传递参数.当到达Test.ps1脚本时,带有空格的路径被拆分.

powershell.exe -noprofile -noexit -command "& {c:\test1.ps1 $args}"
Run Code Online (Sandbox Code Playgroud)

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

Nic*_*ick 29

我意识到这个问题现在已经有几年了,但是因为它仍然是许多谷歌查询通过资源管理器拖放运行PowerShell的最佳结果我想我今天发布了我想出的内容希望它能帮助别人.

我希望能够将文件拖放到PowerShell(ps1)脚本上,并且找不到任何好的解决方案(没有任何不需要额外的脚本或快捷方式).我开始在注册表中查找文件的同事,我想出了一些看似完美的东西.

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

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

此删除处理程序是Windows Scripting Host使用的处理程序.这是我的第一选择,因为它支持长文件名.如果你遇到空格或其他问题,你可以尝试标准的Shell32可执行文件(.exe,.bat等)drop handler : {86C86720-42A0-1069-A2E8-08002B30309D}.

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

通过修改PS1文件的Open动词来更改此行为:

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

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

而已.我没有做过任何广泛的测试,但到目前为止它似乎工作得很好.我可以删除单个文件/文件夹以及组.参数列表中文件的顺序并不总是您所期望的(资源管理器如何命令所选文件),但除此之外它似乎是理想的.您还可以创建PS1文件的快捷方式Shell:Sendto,允许您使用"发送到"菜单传递文件.

这里是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\" %*"
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 由于这些更改,在资源管理器中双击PS1文件将执行该脚本; 要编辑而不是打开,您必须使用右键单击菜单.并且作为一个建议(遗憾地从苦涩的经验中学习:),如果您的脚本具有破坏性的操作,您可能会考虑确认/理智检查.

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

  • 请记住,除非您使用的是签名脚本,否则您需要更改执行策略(Set-ExecutionPolicy).

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


小智 11

将文件或文件夹传递给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%'"
Run Code Online (Sandbox Code Playgroud)

你所要做的就是

制作.bat文件的副本

给它与脚本文件相同的名称,但扩展名为.bat

例如"hello.ps1"< - >"hello.bat"

将文件/文件夹放到批处理文件中,它会将它们传递给脚本.

示例脚本代码可能如下所示:

"hello world"
$args
$args.Gettype().Fullname
Run Code Online (Sandbox Code Playgroud)

  • 有没有理由不使用单行`powershell.exe -NoExit -Command"&'%~dpn0.ps1'%*"`而不是循环参数?它不处理包含空格的路径,但据我所知,上述批处理脚本也没有. (2认同)

Nat*_*ley 5

我不确定为什么我没有早点想到这个...

自此以来,一直以来的秘密一直是参数属性“ ValueFromRemainingArguments ”。

捷径

powershell.exe -noexit -file c:\Test.ps1
Run Code Online (Sandbox Code Playgroud)

Test.ps1

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

'Paths'
$Path
Run Code Online (Sandbox Code Playgroud)