2013-09-11 2 views
3

Я выполняю следующий код, пытающийся выполнить команду 7z.exe для распаковки файлов.powershell Выполнение внешней команды, не принимающей параметр

$ dir содержит пользовательский ввод пути к zip-файлу, который может содержать пробелы, конечно! и $ dir \ temp2 ниже - это каталог, который я ранее создал.

Get-ChildItem -path $dir -Filter *.zip | 
    ForEach-Object { 
     $zip_path = """" + $dir + "\" + $_.name + """" 
     $output = " -o""$dir\temp2""" 
     &7z e $zip_path $output 
    } 

, когда я исполняю его я получаю следующее из 7z.exe

7-Zip [64] 9.20 Copyright (C) 1999-2010 Игорь Павлов 2010-11-18

обработки архива C: \ тест реж \ test.zip

нет файлов для обработки

файлов: 0 Размер: 0 Сжатый: 50219965

если я затем скопирую значение из $ zip_path и $ output, чтобы сформировать свою собственную строку cmd, РАБОТАЕТ!

, например: 7z е "с: \ тест реж \ test.zip" -o "C: \ выход тест"

сейчас, я могу воспроизвести то же самое сообщение "нет файлов для обработки" я получаю когда я выполняю в powershell, используя следующий cmd в cli.

7z е "с: \ тест реж \ test.zip" о "C: \ тест выхода"

SO, кажется, что PowerShell является удаление приборную полукокса из моей опции -o. и да, это должно быть -o "C: \ test output", а не -o "c: \ test output" с 7z.exe между параметром -o и его значением нет пробела.

Я в тупике, я делаю что-то неправильно или должен ли я делать это по-другому? любые предложения или помощь благодаря

ответ

3

Я никогда не может получить Invoke-Expression (псевдоним = &), чтобы работать правильно либо, так что я узнал, как использовать объект процесса

$7ZExe = (Get-Command -CommandType Application -Name 7z) 
    $7ZArgs = @(
     ('-o"{0}\{1}"' -f $dir, $_.Name), 
     ('"{0}\{1}"' -f $dir, 'temp2') 
    ) 

    [Diagnostics.ProcessStartInfo]$7Zpsi = New-Object -TypeName:System.Diagnostics.ProcessStartInfo -Property:@{ 
     CreateNoWindow = $false; 
     UseShellExecute = $false; 
     Filename = $7ZExe.Path; 
     Arguments = $7ZArgs; 
     WindowStyle = 'Hidden'; 
     RedirectStandardOutput = $true 
     RedirectStandardError = $true 
     WorkingDirectory = $(Get-Location).Path 
    } 

    $proc = [System.Diagnostics.Process]::Start($7zpsi) 
    $7ZOut = $proc.StandardOutput 
    $7ZErr = $proc.StandardError 
    $proc.WaitForExit() 
+0

спасибо вы. это сработало отлично. мне пришлось перевернуть массив args, -o занимает второе место, а первому параметру нужно «e», как это («e» {0} \ {1} "'-f $ dir,' temp2 '). еще раз спасибо –

+0

'&' - оператор вызова, который не анализирует команду (см. ['about_Operators'] (http://go.microsoft.com/fwlink/?LinkID=113242)). Если у вас возникли проблемы с его использованием, тогда пункт ** 1.3 ** или пункт ** 2 ** в [мой ответ на вызов msbuild с вложенными кавычками] (http://stackoverflow.com/a/8468690/2495) могут быть полезны. –

+0

Это решение обладает дополнительным преимуществом, препятствующим хостам проглатывать stderr и stdout. Например, git.exe выдает весь подробный вывод stderr, который заставляет ISE бросать RemoteException или какую-то такую ​​глупость. – Eris

3

я был в состоянии дублировать точный вопрос и попробовал множество комбинаций, избегая переключателя -o и избегая котировок ", а что нет. Но, как один из ответов, мы с SysInternals использовали ProcessMonitor для определения формата, который он передавал в файл 7z.exe. То, что работает в простой командной строке, не работает внутри powershell одинаково. Например, если я попытался построить параметры внутри PowerShell, как и cmdline, это не получится. i.e -o"C:\scripts\so\new folder" не работает. Но если вы включаете -o переключатель внутри кавычек, тогда PowerShell передает строку "-oC:\scripts\so\new folder", которую 7z.exe рад принять. Так я узнал, что 7z.exe будет принимать как форматы, такие как

"C:\Program Files\7-zip\7z.exe" e "C:\scripts\so\new folder.zip" -o"C:\scripts\so\new folder" 

и

"C:\Program Files\7-zip\7z.exe" e "C:\scripts\so\new folder.zip" "-oC:\scripts\so\new folder" 

И это как примеры содержат пробелы в них.

[string]$pathtoexe = "C:\Program Files\7-Zip\7z.exe" 
$dir = "C:\scripts\so" 
$output = "$dir\new folder" 
Get-ChildItem -path $dir -Filter *.zip | % {   
    [array]$marguments = "e",$_.FullName,"-o$output";  
    & $pathtoexe $marguments 
} 

Другой подход в PS V3 заключается в том, чтобы избежать возможности синтаксического анализа powershell.Вы можете использовать команду --%, чтобы сообщить powershell о прекращении разбора таких команд.

$zipfile = "C:\scripts\so\newfolder.zip" 
$destinationfolder = "C:\scripts\so\New Folder" 
[string]$pathtoexe = "C:\Program Files\7-Zip\7z.exe" 
& $pathtoexe --% e "C:\scripts\so\newfolder.zip" -o"C:\scripts\so\new folder" 

Используя --% синтаксис, который вы вводите команды, как и вы должны ввести их в командной строке. Я тестировал эту логику и извлекал файлы в папку назначения.

Чтобы узнать больше о --% проверки PS> help about_parsing

Проблема с этим подходом после --% не представляется возможным включить переменную. Решение этой проблемы состоит в том, чтобы просто включить --% в качестве другой строковой переменной и передать ее следующим образом. И этот подход похож на подход командной строки, который не работал первоначально.

[string]$pathtoexe = "C:\Program Files\7-Zip\7z.exe" 
$dir = "C:\scripts\so" 
$output = "$dir\new folder" 
Get-ChildItem -path $dir -Filter *.zip | % {   
$zipfile = $_.FullName; 
[string]$formated = [System.String]::Concat("e ", """$zipfile"""," -o""$output"""); 
[string]$stopparser = '--%'; 
& $pathtoexe $stopparser $formated; 
} 
+1

Это не решит проблему. '$ Varname' не обрабатывается после' -% ', поэтому он не может использовать имена переменных для аргументов. – Eris

+0

@ Eris Я понял это после публикации и рефакторинга в соответствии с проблемой OP. – Mitul

+0

@ Эрис Я обновил свой ответ после множества попыток. :) спасибо за мотивацию. – Mitul

3

Используя отличную Process Explorer от Windows, Sysinternalssuite я был в состоянии наблюдать некоторые очень интересное поведение. Я упростил командную строку немного, как показано ниже:

dir -Path $dir -Filter *.zip | 
    select FullName | 
    % { & 7za.exe e $_ "-o$dir\tmp" } 

Это было на самом деле, выполнив следующую командную строку в соответствии с Process Explorer:

C:\temp\7za.exe @{FullName="C:\temp\test.zip"} -oC:\temp\test 

Рассказывая PowerShell для расширения сил FULLNAME собственности его из Метод HashMap и рассматривает его как обычную строку, 7-Zip может иметь дело с:

dir -Path $dir -Filter *.zip | 
    select -ExpandProperty FullName | 
    % { & 7za.exe e $_ "-o$dir\tmp" } 

Там все еще может быть и другими вопросы, как дело с пробелами в имени файла что я действительно не рассматривал или не учитывал, но я подумал, что стоит добавить примечание о том, что PowerShell (v2 в данном случае) не совсем передавал параметры, как вы могли ожидать.

+0

+1 для упоминания инструмента Sysinternals. Я пробовал разные варианты раньше и пытался включить только переменную пути внутри кавычек, которые передают неправильные строки в файл 7z.exe. Ты обалденный. – Mitul

Смежные вопросы