Элемент удаления Powershell% 1 (контекстное меню) - PullRequest
0 голосов
/ 23 февраля 2019

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

TL; DR внизу.

Итак, у меня есть проблема,Я пытаюсь добавить сценарий PS в контекстное меню через regedit, который удаляет папку + файлы внутри, он отлично работает на папках без пробелов в нем, но когда я пытаюсь удалить папку с пробелами (например, «Новая папка»), онвыдает ошибку и закрывается.(Попытка поиска команды pause / sleep с Remove-Item, но безуспешно, за исключением длинных сценариев с обработкой ошибок и т. Д.)

Я подозреваю, что ошибка похожа на

Remove-Item : A positional parameter cannot be found that accepts argument 'Folder'.

В строке: 1 символ: 12 + Remove-item <<<< Новая папка + CategoryInfo: InvalidArgument: (:) [Remove-Item], ParameterBindingException + FullyQualifiedErrorId: PositionalParameterNotFound, Microsoft.PowerShell.Commands.RemoveItemCommand </p>

И код, который я сейчас использую:

cmd /c  PowerShell Remove-Item "%1" -recurse -force

Я пробовал разные варианты, чтобы он работал без удачи.IE заменил "%1" на «pathAsString», добавил еще один "% 1", добавил подстановочный знак "* *", убрал флаги.Несколько разных вариантов кода, который я пробовал:

cmd /c PowerShell Remove-Item \"%1\" -recurse -force
cmd /c PowerShell Remove-Item & "{"%1" -recurse -force"}"

TL; DR cmd /c PowerShell Remove-Item "%1" -recurse -force игнорирует папки с пробелами, пробовал разные вещи.Использование в контекстном меню (через Regedit).

Может быть, решение очевидно, но я его не вижу.

Ответы [ 2 ]

0 голосов
/ 24 февраля 2019

Одна из ваших попыток:

cmd /c PowerShell Remove-Item \"%1\" -recurse -force

на самом деле работает , хотя только если те пути, которые имеют встроенные пробелы, неt содержат несколько соседних пробелов (см. нижнюю часть, чтобы узнать, почему ваша первая попытка с "%1" вместо \"%1\" не сработала).

To сделать команду устойчивой (и также более эффективной), использовать следующий вариант, который делает не включает cmd.exe (потому что это не обязательно), и команда для передачи в PowerShell заключена в "..." в целом с внедренным ", экранированным как \" (как в вашей попытке):

powershell.exe -noprofile -command "Remove-Item -LiteralPath \"%1\" -Recurse -Force"

Используемые параметры интерфейса командной строки PowerShell:

  • -noprofile подавляет загрузку профиля текущего пользователя ($PROFILE), чтотолько излишне замедлять выполнение команды (или, что еще хуже, может изменить ее поведение).

  • -command сообщает PowerShell, что остальные аргументыкоманда PowerShell (фрагмент исходного кода, в отличие от -file, который используется для вызова script )

    • Хотя указывать * не нужно1056 * в Windows PowerShell, поскольку это подразумевается , это больше не относится к PowerShell Core , который по умолчанию равен -file.

Команда Remove-Item, переданная в PowerShell:

  • Включение всей PowerShell команды в "..."гарантирует, что пробел внутри команды сохраняется как есть , что имеет значение с путями, которые могут содержать серии из нескольких пробелов, например "c:\Users\jdoe\Invoices<space><space>2018"

  • \"Вот как PowerShell требует вложенных (встроенных) " символов.с экранированием при вызове из командной строки с -command - см. объяснение ниже.

  • -LiteralPath гарантирует, что Remove-Itemинтерпретирует путь буквально , а не как шаблон с подстановочными знаками (как это происходит по умолчанию с подразумеваемым параметром -Path);хотя маловероятно, что такие пути, как c:\tmp\folder[], будут нарушать команду, если они будут приняты в качестве символа подстановки.

Предостережения :

  • Из-за (в конечном итоге) использования двойных кавычек ("...") для включения пути (путь к каталогу, в который File Explorer расширяет %1), он становится расширяемой строкой , т. Е.при условии строковой интерполяции , что означает, что пути к папкам, которые содержат $ символов (например, c:\tmp\$foo), могут быть неправильно истолкованы.

  • Вы можете подавить эту интерполяциюзаменив \"%1\" на '%1', т. е. используя строку в одинарных кавычках (что PowerShell всегда обрабатывает буквально), но проблема в том, что вы не сможете использовать команду напапки, пути которых имеют ' символов.в них (например, c:\tmp\o'reilly)


Почему просто "%1" недостаточно:

cmd /c PowerShell Remove-Item "%1" -recurse -force, ваша (первая) командная строка(который вы используете как определение команды для контекстных меню File Explorer ), обрабатывается следующим образом:

  • File Explorer заменяет %1 на абсолютный путьфайла для папки, которая была нажата правой кнопкой мыши, как есть - независимо от того, есть ли в пути встроенные пробелы;Например:

    • c:\Users\jdoe\Invoices 2018.
  • Затем выполняется результирующая командная строка;Например:

    • cmd /c PowerShell Remove-Item "c:\Users\jdoe\Invoices 2018" -recurse -force
  • cmd /c здесь является второстепенным (и не обязательным): по сути, он просто передает командную строку в PowerShell(через исполняемый файл powershell.exe);Например:

    • powershell.exe Remove-Item "c:\Users\jdoe\Invoices 2018" -recurse -force
  • PowerShell first обрабатывает отдельные аргументы - Remove-Item, "c:\Users\jdoe\Invoices 2018", -recurse, -force с помощью без двойных кавычек .

  • Поскольку подразумевается опция -command, аргументы с кавычками воссоединяются с пробелом в качестве разделителя, а затем интерпретируется как фрагмент исходного кода PowerShell ;Например:

    • Remove-Item c:\Users\jdoe\Invoices 2018 -recurse -force

    • Как видите, удаление двойных кавычек привело к неправильной команде PowerShell, поскольку путьс пробелами теперь отсутствует кавычка, так что c:\Users\jdoe\Invoices 2018 больше не распознается как одиночный аргумент и вместо этого интерпретируется как 2 аргументы, префикс c:\Users\jdoe\Invoices с последующим 2018 как его собственный, синтаксически посторонний аргумент.

    • Использование \"%1\" вместо "%1" предотвратит предварительное удаление кавычек - сообщая PowerShell, что символы " имеют символ.должны быть сохранены во время первоначального анализа аргумента - кроме того, для правильного сохранения путей к файлам с несколькими соседними пробелами необходимо дополнительно заключить в себя всю команду PowerShell в "..."хотя такие пути могут быть результатом опечатки во время создания папки):

      • Без в целом "...", путь \" в кавычках, такой как C:\Users\jdoe\Invoices<space><space>2018 приведет к следующим 2 аргументам:

        • \"C:\Users\jdoe\Invoices
        • 2018\"
        • Когда позже PowerShell повторно присоединится котдельные аргументы с одинарным пробелом между ними (после признания \" как экранированного " как сохраненного ), до интерпретируя полученную строку как код PowerShell, он видит "C:\Users\jdoe\Invoices<space>2018", т. е. только один пробел.
      • С в целом "..." вся команда PowerShell анализируется как single аргумент с внутренние пробелы сохранены как есть , что позволяет избежать проблемы.

0 голосов
/ 23 февраля 2019

У меня сработало следующее:

cmd /c PowerShell -command "& {Remove-Item -path '%1' -recurse -force -confirm:$false}"

При использовании cmd.exe такой вещи, как блок скрипта, не существует.Это означает, что значение, переданное -command, всегда будет строкой.Я добавил одинарные кавычки ('') вокруг %1, чтобы сохранить ваши двойные кавычки ("") с вашим аргументом.По-видимому, этот метод потерпит неудачу, если в пути к файлу будет одиночная кавычка (').Также оператор вызова & не требуется, хотя в онлайн-документации сказано, что это так.

См. Справка командной строки PowerShell.exe для получения дополнительной информации об использовании PowerShell.exe.

См. О правилах цитирования для получения дополнительной информации.о том, как работают одинарные и двойные кавычки PowerShell.

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