Обработка команд Powershell (передача переменных)

Я создаю сценарий 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

person GabeA    schedule 30.04.2009    source источник


Ответы (6)


Оператор вызова '&' в этом случае не нужен. Он используется для вызова команды в новой области. Обычно это используется для вызова команды, заданной строкой или блоком сценария. У этого также есть дополнительное преимущество, заключающееся в том, что любые переменные, созданные, скажем, в сценарии PowerShell, отбрасываются после завершения команды и исчезновения области действия.

Однако, поскольку cmd является EXE-файлом, он выполняется в совершенно другом процессе. FWIW, вы получаете аналогичный вывод непосредственно из 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 и указал ее, например:

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» (выполняемая команда).

person Keith Hill    schedule 01.05.2009
comment
Массивы также хорошо подходят для построения аргументов командной строки; то есть $cmdArgs = @('/c','echo foo'); команда $cmdArgs - person Emperor XLII; 03.05.2009

В прошлом у меня были проблемы с оператором & call при попытке вызвать команды исполняемого типа, как вы пытаетесь. Не уверен, что понимаю, почему. Однако Invoke-Expression всегда работает в этом контексте:

PS C:\> $cmd = "cmd /c echo foo"
PS C:\> Invoke-expression $cmd
foo
person zdan    schedule 01.05.2009

Еще один способ, который я нашел для этого, заключался в создании массива аргументов для командной строки и использовании его с оператором apersand & call. Что-то вроде этого:

$exe = "cmd";
[Array]$params = "/c", "echo", "foo";

& $exe $params;

Это сработало хорошо для меня.

Первоначально я нашел эту технику здесь: http://techstumbler.blogspot.com/2009/12/windows-commands-with-arguments-in.html

person Tom Hazel    schedule 09.12.2009

Ваш последний пример не работает, потому что "&" обрабатывает строку как один аргумент, поэтому он ищет программу с именем "cmd /c echo foo.exe". :)

Это работает:

& $cmd $params

Что касается проблемы с двойными кавычками, похоже, что cmd не нравятся кавычки вокруг аргументов, которые ставит PowerShell. Получается это:

cmd "/c echo foo"

Поэтому я думаю, что он обрабатывает все после /c как точную команду, так что вот так:

echo foo"

Некоторые программы командной строки и непонятный анализ командной строки (именно поэтому PowerShell берет на себя эту работу для функций и командлетов). В случае cmd я бы предложил следующее:

$param = "echo foo"
& cmd /c $param
person JasonMArcher    schedule 01.05.2009

я думаю, это артефакт использования cmd /c. Бег

$param = "echo foo"
cmd /c $param

работает отлично. Если у вас нет реального примера кода, устранить неполадки довольно сложно.

person Orihara    schedule 01.05.2009

Аргументы обрабатываются по-разному, когда они содержатся в строке:

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
person cmcginty    schedule 20.12.2012