Выполнение команды 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'