it-swarm.com.ru

Как запустить EXE-файл в PowerShell с параметрами с пробелами и кавычками

Как запустить следующую команду в PowerShell?

C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb: sync -source: dbfullsql = "Источник данных = mysource; Интегрированная безопасность = false; ID пользователя = sa; Pwd = sapass!; База данных = mydb;" -dest: dbfullsql = "Источник данных =.\mydestsource; Интегрированная безопасность = false; ID пользователя = sa; Pwd = sapass!; База данных = mydb;", имя_компьютера = 10.10.10.10, имя пользователя = администратор, пароль = adminpass "

255
Vans

Когда PowerShell видит команду, начинающуюся со строки, он просто оценивает строку, то есть обычно выводит ее на экран, например:

PS> "Hello World"
Hello World

Если вы хотите, чтобы PowerShell интерпретировал строку как имя команды, используйте оператор вызова (&) следующим образом:

PS> & 'C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe'

После этого вам, вероятно, нужно только заключить в кавычки пары параметров/аргументов, которые содержат пробелы и/или символы кавычек. Когда вы вызываете такой EXE-файл со сложными аргументами командной строки, обычно очень полезно иметь инструмент, который покажет вам, как PowerShell отправляет аргументы в EXE-файл. PowerShell Community Extensions имеет такой инструмент. Это называется эхомарки. Вы просто замените EXE-файл на echoargs, оставив все аргументы на месте, и он покажет вам, как EXE-файл получит эти аргументы, например:

PS> echoargs -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass

Arg 0 is <-verb:sync>
Arg 1 is <-source:dbfullsql=Data>
Arg 2 is <Source=mysource;Integrated>
Arg 3 is <Security=false;User>
Arg 4 is <ID=sa;Pwd=sapass!;Database=mydb;>
Arg 5 is <-dest:dbfullsql=Data>
Arg 6 is <Source=.\mydestsource;Integrated>
Arg 7 is <Security=false;User>
Arg 8 is <ID=sa;Pwd=sapass!;Database=mydb; computername=10.10.10.10 username=administrator password=adminpass>

Используя echoargs, вы можете экспериментировать, пока не поймете это правильно, например:

PS> echoargs -verb:sync "-source:dbfullsql=Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;"
Arg 0 is <-verb:sync>
Arg 1 is <-source:dbfullsql=Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;>

Оказывается, я слишком старался, чтобы сохранить двойные кавычки вокруг строки подключения. Очевидно, что в этом нет необходимости, потому что даже cmd.exe удалит их.

Кстати, снимаю шляпу перед командой PowerShell. Они очень помогли мне показать конкретное заклинание одинарных и двойных кавычек, чтобы получить желаемый результат - если вам нужно было сохранить внутренние двойные кавычки на месте. :-) Они также понимают, что это область боли, но они движимы количеством людей, затронутых конкретной проблемой. Если это для вас проблема, то, пожалуйста, проголосуйте за это сообщение об ошибке PowerShell .

Для получения дополнительной информации о том, как PowerShell выполняет синтаксический анализ, обратитесь к моей серии эффективных блогов PowerShell - в частности пункт 10 - "Понимание режимов синтаксического анализа PowerShell"

ОБНОВЛЕНИЕ 4/4/2012: С этой ситуацией намного легче справиться в PowerShell V3. Смотрите это сообщение в блоге для деталей .

280
Keith Hill

Просто добавьте оператор & перед именем .exe. Вот команда для установки SQL Server Express в режиме молчания:

$fileExe = "T:\SQLEXPRADV_x64_ENU.exe"
$CONFIGURATIONFILE = "T:\ConfSetupSql2008Express.ini"

& $fileExe  /CONFIGURATIONFILE=$CONFIGURATIONFILE
48
nonolde1er

У меня были пробелы как в команде, так и в параметрах, и вот что у меня сработало:

$Command = "E:\X64\Xendesktop Setup\XenDesktopServerSetup.exe"
$Parms = "/COMPONENTS CONTROLLER,DESKTOPSTUDIO,DESKTOPDIRECTOR,LICENSESERVER,STOREFRONT /PASSIVE /NOREBOOT /CONFIGURE_FIREWALL /NOSQL"

$Prms = $Parms.Split(" ")
& "$Command" $Prms

По сути, это то же самое, что и ответ Акиры, но это работает, если вы динамически строите параметры вашей команды и помещаете их в переменную.

36
Microb

Это сработало для меня:

& 'D:\Server\PSTools\PsExec.exe' @('\\1.1.1.1', '-accepteula', '-d', '-i', $id, '-h', '-u', 'domain\user', '-p', 'password', '-w', 'C:\path\to\the\app', 'Java', '-jar', 'app.jar')

Просто поместите пути или строки соединения в один элемент массива и разбейте остальные элементы в одном элементе массива каждый.

Здесь есть много других вариантов: https://social.technet.Microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx

Microsoft должна сделать этот способ более простым и совместимым с синтаксисом командной строки.

15
Akira Yamamoto

Смотрите эту страницу: https://slai.github.io/posts/powershell-and-external-commands-done-right/

Сводка с использованием vshadow в качестве внешнего исполняемого файла:

$exe = "H:\backup\scripts\vshadow.exe"
&$exe -p -script=H:\backup\scripts\vss.cmd E: M: P:
12
Baodad

В случае, если кому-то интересно, как запустить исполняемый файл:

.....>.\file.exe

или же 

......> full\path\to\file.exe

9
darkgaze

Мне удалось заставить мою подобную команду работать, используя следующий подход:

msdeploy.exe -verb=sync "-source=dbFullSql=Server=THESERVER;Database=myDB;UID=sa;Pwd=saPwd" -dest=dbFullSql=c:\temp\test.sql

Для вашей команды (не то, чтобы это сильно помогло сейчас) все будет выглядеть примерно так: 

msdeploy.exe -verb=sync "-source=dbfullsql=Server=mysource;Trusted_Connection=false;UID=sa;Pwd=sapass!;Database=mydb;" "-dest=dbfullsql=Server=mydestsource;Trusted_Connection=false;UID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass

Ключевые моменты:

  • Используйте кавычки вокруг исходного аргумента и удаляйте встроенные кавычки вокруг строки подключения 
  • Используйте альтернативные имена ключей при построении строки подключения SQL, в которой нет пробелов. Например, используйте «UID» вместо «User Id», «Server» вместо «Data Source», «Trusted_Connection» вместо «Integrated Security» и т.д. Я смог заставить его работать только после удаления всех пробелов из строки подключения.

Я не пытался добавить часть «computername» в конце командной строки, но, надеюсь, эта информация поможет другим, читающим это, приблизиться к желаемому результату.

8
G-Mac

Новая escape-строка в PowerShell V3, цитируемая Новые возможности языка V3:

Более простое повторное использование командных строк из Cmd.exe

В Интернете полно командных строк, написанных для Cmd.exe. Эти командные строки работают достаточно часто в PowerShell, но когда они содержат определенные символы, например, точку с запятой (;), знак доллара ($) или фигурные скобки, вы должны внести некоторые изменения, возможно, добавив некоторые кавычки. Это, казалось, было источником многих незначительных головных болей.

Чтобы помочь решить этот сценарий, мы добавили новый способ «избежать» анализа командных строк. Если вы используете магический параметр -%, мы прекращаем обычный синтаксический анализ вашей командной строки и переключаемся на что-то гораздо более простое. Мы не сопоставляем кавычки. Мы не останавливаемся на точке с запятой. Мы не расширяем переменные PowerShell. Мы расширяем переменные среды, если вы используете синтаксис Cmd.exe (например,% TEMP%). Кроме этого, аргументы до конца строки (или канала, если вы передаете) передаются как есть. Вот пример:

PS> echoargs.exe --% %USERNAME%,this=$something{weird}
Arg 0 is <jason,this=$something{weird}>
6
Loïc MICHEL

Есть немало методов, которые вы можете использовать для этого.

Существуют и другие методы, такие как использование оператора вызова (&), командлета Invoke-Expression и т.д. Но они считаются небезопасными. Microsoft рекомендует использовать Start-Process.

Метод 1

Простой пример

Start-Process -NoNewWindow -FilePath "C:\wamp64\bin\mysql\mysql5.7.19\bin\mysql" -ArgumentList "-u root","-proot","-h localhost"

В твоем случае

Start-Process -NoNewWindow -FilePath "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -ArgumentList "-verb:sync","-source:dbfullsql=`"Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`"","-dest:dbfullsql=`"Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`"","computername=10.10.10.10","username=administrator","password=adminpass"

В этом методе вы разделяете каждый параметр в ArgumentList с помощью запятых.

Метод 2

Простой пример

Start-Process -NoNewWindow -FilePath "C:\wamp64\bin\mysql\mysql5.7.19\bin\mysql" -ArgumentList "-u root -proot -h localhost"

В твоем случае

Start-Process -NoNewWindow -FilePath "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -ArgumentList "-verb:sync -source:dbfullsql=`"Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`" -dest:dbfullsql=`"Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`",computername=10.10.10.10,username=administrator,password=adminpass"

Этот метод проще, так как позволяет вводить параметры за один раз.

Обратите внимание, что в powershell для представления кавычки (") в строке необходимо вставить Grave accent (`) (это клавиша над клавишей Tab на клавиатуре США).

-NoNewWindow Параметр используется для отображения нового процесса в текущем окне консоли. По умолчанию Windows PowerShell открывает новое окно.

Ссылки: Powershell/Scripting/Start-Process

4
Missaka Iddamalgoda

Я перепробовал все предложения, но все еще не смог запустить msiexec.exe с параметрами, которые содержали пробелы. Таким образом, мое решение закончилось использованием System.Diagnostics.ProcessStartInfo:

# can have spaces here, no problems
$settings = @{
  CONNECTION_STRING = "... ..."
  ENTITY_CONTEXT = "... ..."
  URL = "..."
}

$settingsJoined = ($settings.Keys | % { "$_=""$($settings[$_])""" }) -join " "
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.WorkingDirectory = $ScriptDirectory
$pinfo.FileName = "msiexec.exe"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = "/l* install.log /i installer.msi $settingsJoined"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
4
Daniel Lidström

Альтернативный ответ - использовать Base64 кодированный командный ключ:

powershell -EncodedCommand "QwA6AFwAUAByAG8AZwByAGEAbQAgAEYAaQBsAGUAcwBcAEkASQBTAFwATQBpAGMAcgBvAHMAbwBmAHQAIABXAGUAYgAgAEQAZQBwAGwAbwB5AFwAbQBzAGQAZQBwAGwAbwB5AC4AZQB4AGUAIAAtAHYAZQByAGIAOgBzAHkAbgBjACAALQBzAG8AdQByAGMAZQA6AGQAYgBmAHUAbABsAHMAcQBsAD0AIgBEAGEAdABhACAAUwBvAHUAcgBjAGUAPQBtAHkAcwBvAHUAcgBjAGUAOwBJAG4AdABlAGcAcgBhAHQAZQBkACAAUwBlAGMAdQByAGkAdAB5AD0AZgBhAGwAcwBlADsAVQBzAGUAcgAgAEkARAA9AHMAYQA7AFAAdwBkAD0AcwBhAHAAYQBzAHMAIQA7AEQAYQB0AGEAYgBhAHMAZQA9AG0AeQBkAGIAOwAiACAALQBkAGUAcwB0ADoAZABiAGYAdQBsAGwAcwBxAGwAPQAiAEQAYQB0AGEAIABTAG8AdQByAGMAZQA9AC4AXABtAHkAZABlAHMAdABzAG8AdQByAGMAZQA7AEkAbgB0AGUAZwByAGEAdABlAGQAIABTAGUAYwB1AHIAaQB0AHkAPQBmAGEAbABzAGUAOwBVAHMAZQByACAASQBEAD0AcwBhADsAUAB3AGQAPQBzAGEAcABhAHMAcwAhADsARABhAHQAYQBiAGEAcwBlAD0AbQB5AGQAYgA7ACIALABjAG8AbQBwAHUAdABlAHIAbgBhAG0AZQA9ADEAMAAuADEAMAAuADEAMAAuADEAMAAsAHUAcwBlAHIAbgBhAG0AZQA9AGEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIALABwAGEAcwBzAHcAbwByAGQAPQBhAGQAbQBpAG4AcABhAHMAcwAiAA=="

После декодирования вы увидите, что это оригинальный фрагмент OP со всеми аргументами и двойными кавычками.

powershell.exe -EncodedCommand

Accepts a base-64-encoded string version of a command. Use this parameter
to submit commands to Windows PowerShell that require complex quotation
marks or curly braces.

Оригинальная команда:

 C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass"

Это превращается в это, когда закодировано как Base64:

QwA6AFwAUAByAG8AZwByAGEAbQAgAEYAaQBsAGUAcwBcAEkASQBTAFwATQBpAGMAcgBvAHMAbwBmAHQAIABXAGUAYgAgAEQAZQBwAGwAbwB5AFwAbQBzAGQAZQBwAGwAbwB5AC4AZQB4AGUAIAAtAHYAZQByAGIAOgBzAHkAbgBjACAALQBzAG8AdQByAGMAZQA6AGQAYgBmAHUAbABsAHMAcQBsAD0AIgBEAGEAdABhACAAUwBvAHUAcgBjAGUAPQBtAHkAcwBvAHUAcgBjAGUAOwBJAG4AdABlAGcAcgBhAHQAZQBkACAAUwBlAGMAdQByAGkAdAB5AD0AZgBhAGwAcwBlADsAVQBzAGUAcgAgAEkARAA9AHMAYQA7AFAAdwBkAD0AcwBhAHAAYQBzAHMAIQA7AEQAYQB0AGEAYgBhAHMAZQA9AG0AeQBkAGIAOwAiACAALQBkAGUAcwB0ADoAZABiAGYAdQBsAGwAcwBxAGwAPQAiAEQAYQB0AGEAIABTAG8AdQByAGMAZQA9AC4AXABtAHkAZABlAHMAdABzAG8AdQByAGMAZQA7AEkAbgB0AGUAZwByAGEAdABlAGQAIABTAGUAYwB1AHIAaQB0AHkAPQBmAGEAbABzAGUAOwBVAHMAZQByACAASQBEAD0AcwBhADsAUAB3AGQAPQBzAGEAcABhAHMAcwAhADsARABhAHQAYQBiAGEAcwBlAD0AbQB5AGQAYgA7ACIALABjAG8AbQBwAHUAdABlAHIAbgBhAG0AZQA9ADEAMAAuADEAMAAuADEAMAAuADEAMAAsAHUAcwBlAHIAbgBhAG0AZQA9AGEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIALABwAGEAcwBzAHcAbwByAGQAPQBhAGQAbQBpAG4AcABhAHMAcwAiAA==

а вот как тиражировать дома:

$command = 'C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass"'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
$encodedCommand

#  The clip below copies the base64 string to your clipboard for right click and paste.
$encodedCommand | Clip
3
Knuckle-Dragger

Это сработало для меня:

PowerShell.exe -Command "& ""C:\Some Script\Path With Spaces.ps1"""

Кажется, что ключ заключается в том, что вся команда заключена во внешние кавычки, амперсанд «&» используется для указания того, что выполняется другой дочерний файл команды, а затем, наконец, экранированные (doubled-double-) кавычки вокруг имени пути/файла с пробелами Вы хотели выполнить в первую очередь.

Это также завершение единственного обходного пути к проблеме подключения MS, при котором -File не передает обратно ненулевые коды возврата и -Command является единственной альтернативой. Но до сих пор считалось, что ограничением -Command было то, что оно не поддерживает пробелы. Я тоже обновил этот элемент обратной связи.

http://connect.Microsoft.com/PowerShell/feedback/details/750653/powershell-exe-doesn-t-return-correct-exit-codes-when-using-the-file-option

3
Tony Wall

Вы можете запускать exe-файлы в PowerShell различными способами. Например, если вы хотите запустить unrar.exe и извлечь файл .rar, вы можете просто написать в powershell это:

$extract_path = "C:\Program Files\Containing folder";
$rar_to_extract = "C:\Path_to_Arch\file.rar"; #(or.exe if its a big file)  
C:\Path_here\Unrar.exe x -o+ -c- $rar_to_extract $extract_path;

Но иногда это не работает, поэтому вы должны использовать параметр &, как показано выше: Например, с vboxmanage.exe (инструментом для управления виртуальными машинами виртуальных ящиков) вы должны вызывать параметры вне строки, например: без кавычек:

> $vmname = "misae_unrtes_1234123"; #(name too long, we want to change this)
> & 'C:\Program Files\Oracle\VirtualBox\VBoxManage.exe' modifyvm $vmname --name UBUNTU;

Если вы хотите просто вызвать заархивированный файл winrar как файлы .exe, вы также можете разархивировать его с помощью командлета invoke-command и параметра Silent/S (он будет извлечен в той же папке, в которой он был сжат).

> Invoke-Command -ScriptBlock { C:\Your-path\archivefile.exe /S };

Таким образом, существует несколько способов запуска файлов .exe с аргументами в powershell.

Иногда нужно найти обходной путь, чтобы заставить его работать должным образом, что может потребовать дополнительных усилий и усилий :) в зависимости от того, как .exe был скомпилирован или сделан его создателями.

2
Andy McRae

У меня был следующий код отлично работает на моем ноутбуке:

& $msdeploy `
-source:package="$publishFile" `
-dest:auto,computerName="$server",includeAcls="False",UserName="$username",Password="$password",AuthType="$auth" `
-allowUntrusted  `
-verb:sync  `
-enableRule:DoNotDeleteRule `
-disableLink:AppPoolExtension  `
-disableLink:ContentExtension  `
-disableLink:CertificateExtension  `
-skip:objectName=filePath,absolutePath="^(.*Web\.config|.*Environment\.config)$" `
-setParam:name=`"IIS Web Application Name`",value="$appName"

Затем, когда я попытался запустить это непосредственно на одном сервере, я начал получать эти ошибки "Unrecognized argument ...etc.... All arguments must begin with "-". "

Перепробовав все возможные обходные пути (безуспешно), я обнаружил, что Powershell на сервере (Windows 2008 R2) был версии 3.0, а на моем ноутбуке - 5.0. (вы можете использовать "$ PSVersionTable", чтобы увидеть версию).

После обновления Powershell до последней версии он снова заработал.

1
drizin

Итак, я столкнулся с подобной проблемой и решил решить ее следующим образом:

  1. Избегайте кавычек (") с помощью символа обратной черты (`)
  2. Окружите свое новое выражение кавычками (")
  3. Используя оператор вызова (&), введите команду invoke-expression для новой строки

Пример решения:

& {invoke-expression "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb: sync -source: dbfullsql =` "Источник данных = mysource; Интегрированная безопасность = false; ID пользователя = sa; Pwd = sapass !; База данных = mydb; `" -dest: dbfullsql = `" Источник данных =.\Mydestsource; Интегрированная безопасность = false; ID пользователя = sa; Pwd = sapass!; База данных = mydb; `", имя_компьютера = 10.10.10.10, имя пользователя = администратор, пароль = adminpass` ""}

0
Randall Borck

Для имени исполняемого файла можно использовать командлет new-alias, чтобы избежать использования пробелов или необходимости добавлять исполняемый файл в среду $ PATH.

PS> new-alias msdeploy "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe"
PS> msdeploy ...

Чтобы перечислить или изменить псевдонимы PS также см.

PS> get-alias
PS> set-alias

От Джеффри Хикс Aarticle

Другие ответы касаются аргументов.

0
crokusek

Я использую этот простой, чистый и эффективный метод.

Я помещаю аргументы в массив, по 1 на строку. Таким образом, его очень легко читать и редактировать. Затем я использую простой прием передачи всех аргументов внутри двойных кавычек в функцию с одним единственным параметром. Это объединяет их, включая массивы, в одну строку, которую я затем выполняю, используя PS «Invoke-Expression». Эта директива специально предназначена для преобразования строки в команду runnable. Работает хорошо:

                    # function with one argument will flatten 
                    # all passed-in entries into 1 single string line
Function Execute($command) {
                    # execute:
    Invoke-Expression $command;
                    # if you have trouble try:
  # Invoke-Expression "& $command";
                    # or if you need also output to a variable
  # Invoke-Expression $command | Tee-Object -Variable cmdOutput;

}

#  ... your main code here ...

               # The name of your executable app
$app = 'my_app.exe';
               # List of arguments:
               #    Notice the type of quotes - important !
               #    Those in single quotes are normal strings, like 'Peter'
$args = 'arg1',
        'arg2',
        $some_variable,
        'arg4',
        "arg5='with quotes'",
        'arg6',
        "arg7 \ with \ $other_variable",
        'etc...';

               # pass all arguments inside double quotes
Execute "$app $args";
0
Felix