代码之家  ›  专栏  ›  技术社区  ›  Nathan Hartley

拖放到PowerShell脚本

  •  15
  • Nathan Hartley  · 技术社区  · 16 年前

    我以为我对此有了答案,但我玩得越多,就越觉得它是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 要使用以下快捷方式命令行,但它没有正确传递参数。带有空格的路径在到达test.ps1脚本时被分开。

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

    有没有人找到一种不用额外脚本就能做到这一点的方法?

    6 回复  |  直到 8 年前
        1
  •  25
  •   Tuill Nick    8 年前

    我意识到这个问题已经存在几年了,但是由于它仍然是许多谷歌查询的头号结果,这些查询都是通过浏览器拖放来运行PowerShell的,所以我想我今天会发布我的想法,希望它能帮助其他人。

    我希望能够将文件拖放到PowerShell(PS1)脚本上,但找不到任何好的解决方案(任何不涉及额外脚本或快捷方式的解决方案)。我开始在注册表中查找文件助理,我想出了一个似乎工作得很好的方法。

    首先,我们需要为.ps1文件添加一个DropHandler条目,这样资源管理器就知道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} .

    这两个放置处理程序都是通过为文件类型(被看作是 (Default) shell键的值)。对于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 选择权。

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

    以下两个注册表文件格式的更改:

    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\ . 另一个需要小心的原因。

    • 记住你需要改变你的 Execution Policy (设置executionpolicy)除非使用签名脚本。

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

        2
  •  9
  •   Thomas Jüttner    15 年前

    将文件或文件夹传递到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文件

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

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

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

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

    "hello world"
    $args
    $args.Gettype().Fullname
    
        3
  •  3
  •   Nathan Hartley    9 年前

    我不知道为什么我没有早点想到这个…

    秘密一直以来都是参数属性,因为它是可用的。” ValueFromRemainingArguments “。

    捷径

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

    PS1

    param (
        [Parameter(ValueFromRemainingArguments=$true)]
        $Path
    )
    
    'Paths'
    $Path
    
        4
  •  1
  •   Keith Hill    16 年前

    更改此的快捷方式并尝试:

    powershell.exe -noprofile -noexit -command "& {c:\test1.ps1 $args}"
    
        5
  •  1
  •   Nathan Hartley    16 年前

    我已经申请了 bug report Powershell Microsoft Connect 站点。

        6
  •  0
  •   Community Mohan Dere    9 年前

    不幸的是, $args 将在空格上拆分参数,从而错误地处理包含这些参数的文件名。但是,您仍然可以处理 $ARGS 在没有外部包装脚本的.ps1中!

    由于在快捷方式上拖放的所有内容(或选择“发送到”)都将作为绝对路径的空间连接列表传递给脚本,因此可以分析 $ARGS 对于使用regex的所有绝对路径引用,并将其传输到foreach:

    $pattern = '([a-zA-Z]:\\(((?![<>:"/\\|?*]).)+((?<![ .])\\)?)*)(\s|$)'
    
    Select-String "$pattern" -input "$args" -AllMatches | Foreach {$_.matches} | ForEach-Object { 
        $path = "$($_.Groups.Groups[1].Value)"
        # ...
    } 
    

    每个地方 $path 正是一条绝对路径(包括内部有空格的路径)

    绝对文件模式取自 here .

    我用括号将它括起来(以使第一组与实际路径相匹配),并添加了 (\s|$) 结尾处的组,即“空白或字符串结尾”,这是必需的,因为快捷方式参数将用单个空格联接;需要$来匹配参数列表中最后出现的路径。

    推荐文章