Выполнение команды powershell с использованием полного пути и аргументов из командной строки

У меня есть скрипт, который сидит в Program Files папка и принимает аргументы: verbose а также restartЗапуск его из папки работает отлично:

powershell ./<file.ps1> -verbose:$True -restart

Попытка запустить его, используя полный путь, вот где у меня проблемы:

powershell & "C:\Program Files\Folder\<file.ps1> -verbose:$True -restart"

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

Я нашел обходной путь с помощью progra~1 вместо Program Files но я хотел бы решить проблему надлежащим образом.

Что мне не хватает?

2 ответа

Решение

В качестве отступления: часть проблемы, связанной с цитированием, можно было бы избежать, используя переменную окружения $env:ProgramFiles вместо буквального "C:\Program Files\..." в пути к сценарию, который упростил бы команду до:
powershell "& $env:ProgramFiles\Folder\file.ps1 -verbose:$True -restart"


Действительно, для выполнения сценариев, на которые ссылаются буквенные пути со встроенными пробелами в PowerShell, эти пути должны быть заключены в кавычки, а путь в кавычках должен быть передан & или же .

Однако при использовании интерфейса командной строки PowerShell использовать проще -File выполнить скрипт, который делает & ненужно и упрощает цитирование:

powershell -File "C:\Program Files\Folder\file.ps1" -Verbose -Restart

использование -Command только если вам нужно передать фрагмент кода PowerShell:

powershell -Command "& 'C:\Program Files\Folder\file.ps1' -Verbose:$true -Restart"

Важнейшие улучшения вашей попытки:

  • & находится внутри "...", который мешает cmd.exe от интерпретации, прежде чем PowerShell увидит это.

  • Путь к сценарию заключен в кавычки ('...'), так что PowerShell видит путь в кавычках.

Примечание:

  • -Command используется для ясности; в Windows PowerShell его можно опустить (как вы это сделали), потому что это параметр по умолчанию; обратите внимание, однако, что в PowerShell Core по умолчанию теперь -File,

  • Вам не нужно передавать все как единое целое "..." строка, но это концептуально яснее таким образом.

Смотрите ниже для деталей.


Что касается того, что вы пытались:

Выше команда не запускает скрипт; Вместо этого он открывает командную строку PS и при выходе из нее открывает скрипт в блокноте.

Это означает, что вы звоните из cmd.exe (из командной строки или командного файла), где & не заключен в "..." имеет особое значение: это оператор последовательности команд.

То есть ваша команда является эквивалентом следующих 2 команд:

powershell
"C:\Program Files\Folder\file.ps1 -verbose:$True -restart"

Первая команда открывает интерактивный сеанс PowerShell. Только после того, как вы вручную выйдете, будет выполнена 2-я команда.

Обратите внимание, что ваш конкретный симптом предполагает, что вы использовали только "C:\Program Files\Folder\<file.ps1>" без аргументов, как 2-я команда, которая действительно откроет этот файл скрипта как документ, для редактирования.

С аргументами вся строка в двойных кавычках интерпретируется как имя файла, и вы получите обычный ... is not recognized as an internal or external command, operable program or batch file.

Для того, чтобы cmd.exe пройти & до вызываемой команды, она должна быть либо заключена в "..." или за пределами такой строки ^&,

Однако даже устранения одной проблемы недостаточно:

rem # !! Still doesn't work
powershell ^& "C:\Program Files\Folder\file.ps1 -verbose:$True -restart"

Другая проблема заключается в том, что при использовании -Command Параметр CLI, который подразумевается в вашем случае, PowerShell использует следующую логику для обработки аргументов:

  • Каждый аргумент лишен включающего "...", если имеется.
  • Разделенные аргументы объединяются с пробелами.
  • Полученная единственная строка затем выполняется как код PowerShell.

То есть с помощью приведенной выше команды PowerShell попытался выполнить строку со следующим дословным содержанием:

& C:\Program Files\Folder\file.ps1 -verbose:$True -restart

Как видите, путь к файлу скрипта, содержащий пробел, не содержит необходимых кавычек.

У вас есть несколько опций для обеспечения необходимого цитирования по пути к скрипту:


Если вы знаете, что ваш путь к сценарию не содержит ' символы, используйте встроенные '...' процитировать:

powershell -Command "& 'C:\Program Files\Folder\file.ps1' -Verbose:$true -Restart"

Только с одной внешней парой " chars., вам не нужно беспокоиться о cmd.exe непреднамеренная интерпретация ваших аргументов, прежде чем они достигнут PowerShell.

В этом случае вы также можете опустить внешнее цитирование, но это делает аргументы без кавычек восприимчивыми к нежелательной интерпретации cmd.exe (хотя это нормально в этом случае), и обратите внимание, что ' не имеет особого значения в cmd.exe так что в стиле PowerShell '...' строка считается без кавычек cmd.exe:

rem # Works, but generally less robust than the above.
powershell -Command ^& 'C:\Program Files\Folder\file.ps1' -Verbose:$true -Restart

Если вы хотите, чтобы даже пути со встроенными ' символы. работать правильно:

Используйте встроенные двойные кавычки, с " сбежал как \" (Так в оригинале):

powershell -Command "& \"C:\Program Files\Folder\file.ps1\" -Verbose:$true -Restart"

К сожалению, это снова делает строку между \" случаи, подлежащие потенциально нежелательной интерпретации cmd.exe,

Вы можете обойти это, используя \"" (так) вместо этого, но это делает строку между \"" экземпляры, подлежащие нормализации пробелов: то есть несколько пробелов в строке складываются в один.

В Windows PowerShell вы можете избежать этого, используя "^"" (так), но обратите внимание, что в PowerShell Core вы получите то же поведение, что и с \"",

rem # The most robust form in Windows PowerShell.
rem # Still subject to whitespace normalization in PowerShell Core.
powershell -Command "& "^""C:\Program Files\Folder\file.ps1"^"" -Verbose:$true -Restart"

Так что ваша проблема в том, что на пути есть место. Как уже упоминалось, вам нужно разбить его на `перед пробелом.

powershell & 'C:\Program` Files\Folder\<file.ps1> -verbose:$True -restart'
Другие вопросы по тегам