Перетащите в сценарий Powershell - PullRequest
15 голосов
/ 12 мая 2010

Я думал, что у меня есть ответ на этот вопрос, но чем больше я играю с ним, тем больше я вижу в нем недостаток дизайна Powershell.

Я хотел бы перетащить (или использовать механизм отправки), чтобы передать несколько файлов и / или папок в виде массива в скрипт Powershell.

Тестовый скрипт

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

Попытка # 1

Я создал ярлык со следующей командной строкой и перетащил туда несколько файлов. Файлы выглядят как отдельные параметры, которые сначала совпадают с параметрами сценария, а оставшаяся часть помещается в массив $ args.

Ярлык для попытки # 1

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

Wrapper Script

Я обнаружил, что могу сделать это с помощью скрипта-оболочки ...

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

Ярлык для сценария Wrapper

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

Попытки ответов

Кит Хилл сделал отличное предложение использовать следующую комбинацию клавиш, но она не передала аргументы правильно. Пути с пробелами были разделены, когда они пришли к сценарию Test.ps1.

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

Кто-нибудь нашел способ сделать это без дополнительного скрипта?

Ответы [ 6 ]

28 голосов
/ 27 декабря 2012

Я понимаю, что этому вопросу уже пару лет, но, поскольку он по-прежнему является лучшим результатом для большинства запросов Google, касающихся запуска PowerShell с помощью перетаскивания в Проводнике, я решил опубликовать то, что мне пришло с сегодняшним днем ​​в надежде, что это поможет другим.

Я хотел иметь возможность перетаскивать файлы в сценарии PowerShell (ps1) и не мог найти хороших решений (ничего, что не включало бы дополнительный сценарий или ярлык). Я начал осматривать файловых партнеров в реестре и нашел что-то, что, кажется, отлично работает.

Сначала нам нужно добавить запись DropHandler для файлов .PS1, чтобы Explorer знал, что файлы PS1 должны принимать операции перетаскивания. Сделайте это с этим изменением реестра. Возможно, вам придется создать подразделы ShellEx и DropHandler.

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

Этот обработчик отбрасывания используется для Windows Scripting Host. Это мой первый выбор, потому что он поддерживает длинные имена файлов. Если у вас возникли проблемы с пробелами или чем-то еще, вы можете попробовать стандартный обработчик отбрасывания исполняемого файла Shell32 (.exe, .bat и т. Д.): {86C86720-42A0-1069-A2E8-08002B30309D}.

Оба эти обработчика сброса работают, просто вызывая глагол по умолчанию (что происходит, когда вы дважды щелкаете файл) для типа файла (который рассматривается как значение (Default) ключа Shell). В случае файлов PS1 это Open . По умолчанию этот глагол отображает скрипт PowerShell в Блокноте - не очень полезен.

Измените это поведение, изменив глагол Open для файлов 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 упорядочивает выбранные файлы), но в остальном он кажется идеальным. Вы также можете создать ярлык для файла 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\" %*"

Примечания:

  • В результате этих изменений двойной щелчок по файлу PS1 в проводнике запустит скрипт; чтобы редактировать, а не открывать, вам придется использовать меню, вызываемое правой кнопкой мыши. И в качестве предложения (к сожалению, извлеченного из горького опыта :), вы можете рассмотреть вопрос о проверке подтверждения / проверки работоспособности, если у вас есть сценарии, которые выполняют разрушительные действия.

  • Скрипты, запускаемые с помощью перетаскивания, будут иметь начальный рабочий каталог по умолчанию C:\Windows\system32\. Еще одна причина быть осторожным.

  • Помните, что вам нужно будет изменить Политику выполнения (Set-ExecutionPolicy), если вы не используете подписанные сценарии.

  • Если вы настроили обработку файлов .PS1 в Windows 10, вам нужно удалить раздел реестра HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ps1\UserChoice, который переопределит обработку по умолчанию.

11 голосов
/ 27 апреля 2011

Самый простой способ передать файлы или папки в скрипт 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 голосов
/ 23 августа 2017

Я не уверен, почему я не подумал об этом раньше ...

Секрет все это время, с тех пор как он стал доступен, был атрибутом параметра " ValueFromRemainingArguments ".

Ярлык

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

Test.ps1

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

'Paths'
$Path
1 голос
/ 17 мая 2010
1 голос
/ 12 мая 2010

Измените свой ярлык на это и попробуйте:

powershell.exe -noprofile -noexit -command "& {c:\test1.ps1 $args}"
0 голосов
/ 13 января 2016

К сожалению, $args разделит ваши аргументы по пробелам, поэтому будет некорректно работать с именами файлов, содержащими их. Тем не менее, вы все еще можете обрабатывать $args внутри вашего .ps1 без сценария внешней оболочки!

Поскольку все, что вы перетаскиваете по ярлыку (или выбираете для «Отправить»), будет передаваться вашему сценарию в виде объединенного пробелом списка абсолютных путей, вы можете проанализировать $args для всех вхождений абсолютного пути, используя регулярное выражение и труба к foreach:

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

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

Где каждый $path - это ровно один абсолютный путь (в том числе с пробелами внутри)

Абсолютный шаблон файла взят из здесь .

Я обернул его в круглые скобки (чтобы сопоставить первую группу с фактическим путем) и добавил группу (\s|$) в конце, которая является "пробелом или концом строки", необходимой, потому что аргументы ярлыка будут объединены с одним пробелом ; $ требуется для совпадения с последним вхождением пути в списке аргументов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...