Обработка команд Powershell (передача переменных)
-
03-07-2019 - |
Вопрос
Я создаю сценарий Powershell для развертывания некоторого кода, и частью процесса является вызов инструмента сжатия командной строки под названием RAR.EXE для резервного копирования некоторых папок.
Я пытаюсь динамически создать параметры, а затем заставить PowerShell вызвать команду с переменными, но у меня возникают проблемы.Это не работает...
Запустите следующий скрипт, и вы поймете, о чем я говорю.Параметры, передаваемые как переменные, искажаются.Если я передам всю команду + параметры, я получу печально известное сообщение «не распознается как командлет...».
Спасибо за любую помощь!
echo "this should succeed"
& cmd /c echo foo
echo "why does this echo out an additional double quote?"
$param = "/c echo foo"
& cmd "$param"
echo "this does the same"
$param = "/c echo foo"
& cmd $param
echo "escaping the slash doesn't work either..."
$param = "`/c echo foo"
& cmd $param
echo "this fails, but why?"
$cmd = "cmd /c echo foo"
&$cmd
Решение
Оператор вызова «&» в этом случае не нужен.Он используется для вызова команды в новой области.Обычно это используется для вызова команды, указанной в строке или блоке сценария.У этого также есть дополнительное преимущество: любые переменные, созданные, скажем, в сценарии PowerShell, отбрасываются после завершения команды и область видимости исчезает.
Однако, поскольку cmd является EXE-файлом, он выполняется в совершенно другом процессе.Кстати, аналогичный вывод вы получите непосредственно из cmd.exe:
> cmd "/c echo foo"
foo"
Таким образом, дополнительная кавычка в конце — это проблема cmd.exe.Обычно вам нужно хранить команду отдельно от параметров, когда PowerShell выполняет синтаксический анализ для вызова команды, например.
45> & { $foo = "foo" }
46> $foo # Note that $foo wasn't found - it went away with the scope
47> . { $foo = "foo" } # dotting executes in the current scope
48> $foo
foo
Заметным исключением здесь является то, что Invoke-Expression ведет себя как функция «оценить эту строку».Используйте с осторожностью, особенно если пользователь предоставляет строку.Ваш день мог бы быть отстойным, если бы они предоставили «ri C:\ -r».
В этом случае, как предлагали другие, я бы вытащил /c из строки $param string и указал ее, например:
cmd /c $param
Или используйте Invoke-Expression, но будьте осторожны.Кстати, когда вы пытаетесь отладить проблемы с отправкой аргументов в EXE из PowerShell, воспользуйтесь утилитой echoargs в расширениях сообщества PowerShell (http://pscx.codeplex.com).Это очень удобно:
49> $param = "/c echo foo"
50> echoargs $param
Arg 0 is </c echo foo>
Это показывает, что cmd.exe получает «/c echo foo» в качестве одинокий аргумент.«/c» должен быть отдельным аргументом от «echo foo» (команда для выполнения).
Другие советы
В прошлом у меня были проблемы с оператором & call при попытке вызвать команды исполняемого типа, как вы пытаетесь.Не уверен, что понимаю, почему.Однако Invoke-Expression всегда работает в этом контексте:
PS C:\> $cmd = "cmd /c echo foo"
PS C:\> Invoke-expression $cmd
foo
Я нашел еще один способ сделать это — создать массив аргументов для командной строки и использовать его с оператором аперсанда и вызова.Что-то вроде этого:
$exe = "cmd";
[Array]$params = "/c", "echo", "foo";
& $exe $params;
У меня это сработало хорошо.
Первоначально я нашел эту технику здесь:http://techstumbler.blogspot.com/2009/12/windows-commands-with-arguments-in.html
Ваш последний пример не удался, потому что «&» рассматривает строку как один аргумент, поэтому он ищет программу с именем «cmd /c echo foo.exe».:)
Это работает:
& $cmd $params
Что касается проблемы с двойными кавычками, похоже, что cmd не нравятся кавычки вокруг аргументов, которые помещает PowerShell.Получается следующее:
cmd "/c echo foo"
Поэтому я думаю, что все, что идет после /c, рассматривается как точная команда, например:
echo foo"
Некоторые программы командной строки и необычный анализ командной строки (именно поэтому PowerShell берет на себя эту работу для функций и командлетов).В случае cmd я бы предложил следующее:
$param = "echo foo"
& cmd /c $param
Я думаю, это артефакт использования cmd /c.бег
$param = "echo foo"
cmd /c $param
работает отлично.Если у вас нет реального примера кода, устранить неполадки будет сложно.
Аргументы обрабатываются по-разному, если они содержатся в строке:
PS D:\> echo "1 2 3"
1 2 3
PS D:\> echo 1 2 3
1
2
3
Те же результаты возникают, когда вы используете переменную для аргументов:
PS D:\> $param = "1 2 3"
PS D:\> echo $param
1 2 3
РЕШЕНИЕ - использовать массив:
PS D:\> $param = @(1,2,3)
PS D:\> echo $param
1
2
3