Как подавить кавычки в командах PowerShell для исполняемых файлов
Есть ли способ подавить кавычки вокруг каждого аргумента командной строки, которые PowerShell любит генерировать, а затем передавать внешним исполняемым файлам для аргументов командной строки, в которых есть пробелы?
Вот ситуация:
Один из способов распаковать множество инсталляторов - это команда вида:
msiexec /a <packagename> /qn TARGETDIR="<path to folder with spaces>"
Попытка выполнить это из PowerShell оказалась довольно сложной. PowerShell любит заключать параметры с пробелами в двойные кавычки. Следующие строки:
msiexec /a somepackage.msi /qn 'TARGETDIR="c:\some path"'
msiexec /a somepackage.msi /qn $('TARGETDIR="c:\some path"')
$td = '"c:\some path"'
msiexec /a somepackage.msi /qn TARGETDIR=$td
Все результаты в следующей командной строке (как сообщается Win32 GetCommandLine() API):
"msiexec" /a somepackage.msi /qn "TARGETDIR="c:\some path""
Эта командная строка:
msiexec /a somepackage.msi TARGETDIR="c:\some path" /qn
результаты в
"msiexec" /a fooinstaller.msi "TARGETDIR=c:\some path" /qn
Кажется, что PowerShell любит заключать результаты выражений, предназначенных для представления одного аргумента в кавычках, при передаче их во внешние исполняемые файлы. Это прекрасно работает для большинства исполняемых файлов. Тем не менее, MsiExec очень специфичен в отношении правил цитирования, которые он хочет, и не будет принимать ни одну из командных строк, сгенерированных PowerShell для путей, в которых есть пробелы.
Есть ли способ подавить это поведение?
6 ответов
Избегайте внутренних кавычек, как это:
msiexec /a somepackage.msi TARGETDIR=`"c:\some path`" /qn
Вот функция, которую я использую для лучшей обработки нескольких аргументов и аргументов с пробелами и кавычками. Обратите внимание, что в приведенных ниже блоках кода не закрашивайте там, где строки начинаются и заканчиваются правильно, и вы должны использовать `, чтобы экранировать кавычки, которые вы хотите в параметре.
function InstallMSIClient{
$Arguments = @()
$Arguments += "/i"
$Arguments += "`"$InstallerFolder\$InstallerVerFolder\Install.msi`""
$Arguments += "RebootYesNo=`"No`""
$Arguments += "REBOOT=`"Suppress`""
$Arguments += "ALLUSERS=`"1`""
$Arguments += "/passive"
Write-Host "Installing $InstallerVerFolder."
Start-Process "msiexec.exe" -ArgumentList $Arguments -Wait }
В моем блоге есть более полный пример. [ http://www.christowles.com%5D
Поместите весь аргумент в кавычки и избегайте внутренних кавычек. В противном случае PowerShell попытается разобрать его:
msiexec /a <packagename> /qn 'TARGETDIR=\"<path to folder with spaces>\"'
Я только что столкнулся с проблемой. Следующее работало для меня:
&cmd /c "msiexec /i `"$appName.msi`" /l* `"$appName.msi.log`" /quiet TARGETDIR=`"D:\Program Files (x86)\$appName\`""
Ключ выполнял cmd, а не msiexec напрямую. Это имело два преимущества:
- Я мог бы обернуть всю команду msiexec в строку, чтобы она разрешала переменную $appName, все еще используя обратную галочку для экранирования кавычек вокруг TARGETDIR.
- Мне удалось использовать $LastExitCode для проверки успеха / неудачи операции msiexec. По какой-то причине $LastExitCode не устанавливается при непосредственном вызове msiexec (hat-tip: http://web.archive.org/web/20100907072034/http://www.powergui.org/thread.jspa?threadID=13022)
У меня нет ответа, но этот парень, кажется, на что-то.
http://www.eggheadcafe.com/software/aspnet/33777311/problem-escaping-command.aspx
Я не мог заставить это работать для меня.
Вот еще кто-то, кто сообщил о проблеме тоже: _http://powershell.com/cs/forums/p/2809/3751.aspx
Вот еще одна идея от кого-то: _http://www.roelvanlisdonk.nl/? P =1135
Это тоже не сработало для меня...
У меня нет ответа, но этот парень, кажется, на что-то. http://www.eggheadcafe.com/software/aspnet/33777311/problem-escaping-command.aspx
Да, похоже, они нашли решение в конце:
Наконец-то выяснили, как это сделать, используя выражение invoke
$installprop = "TARGETDIR=" + "```"" + $installpath + "```""
invoke-expression "msiexec /i $packagepath $installprop"
Я бы порекомендовал использовать здесь-строку, чтобы избежать необходимости выполнять все экранирование.
$command = @'
msiexec /a <packagename> /qn TARGETDIR="<path to folder with spaces>"
'@
invoke-expression $command