Выполнить «реальную» командную строку из переменной в Powershell - PullRequest
0 голосов
/ 22 мая 2018

Когда я, например, читаю какую-то строку удаления из реестра, например "C:\Program Files (x86)\Opera\Launcher.exe" /uninstall, я могу скопировать ее в командную строку Powershell, поставить перед ней префикс с оператором вызова и выполнить ее.

& "C:\Program Files (x86)\Opera\Launcher.exe" /uninstall

Но

$var = '"C:\Program Files (x86)\Opera\Launcher.exe" /uninstall'
& $var

не работает.Конечно, я могу просто сказать

cmd /c $var

Но неужели нет способа сделать это без дополнительного cmd процесса?

Ответы [ 3 ]

0 голосов
/ 22 мая 2018

Я думаю, что ответ Билла Стюарта - правильный способ сделать это.Если по какой-то причине вы не можете получить ответ Билла на работу, вы можете использовать Invoke-Expression, чтобы сделать это, хотя.

$var = '"C:\Program Files (x86)\Opera\Launcher.exe" /uninstall'
Invoke-Expression "& $var"
0 голосов
/ 08 июля 2018

Чтобы использовать & (или прямой вызов, если имя / путь команды - литерал без кавычек ), имя / путь команды должен быть передан отдельно от его аргументов .
При вызове внешней программы вы можете передать эти аргументы как array .

В приведенном ниже решении используется собственный Write-Output командлет PowerShell в сочетании с - safe - вызовом Invoke-Expression [1] в порядкеразобрать строку в составляющие ее аргументы.

# Gets the arguments embedded in the specified string as an array of literal tokens 
# (applies no interpolation). 
# Note the assumption is that the input string contains no NUL characters 
# (characters whose code point is `0x0`) - which should be a safe assumption
# Example: 
#   get-EmbeddedArguments '"C:\Program Files (x86)\Opera\Launcher.exe" /uninstall'
# yields array @( 'C:\Program Files (x86)\Opera\Launcher.exe', '/uninstall' )
function get-EmbeddedArguments ([string] $String) {
  (Invoke-Expression "Write-Output -- $($String -replace '\$', "`0")") -replace "`0", '$'            #"
}

# Input string.
$var = '"C:\Program Files (x86)\Opera\Launcher.exe" /uninstall'

# Extract the command name (program path) and arguments.
# Note the destructuring assignment that stores the return array's 1st element
# in $exe, and collects the remaining elements, if any, in $exeArgs.
$exe, $exeArgs = get-EmbeddedArguments $var

# Use & to invoke the command (name / program path) ($exe) and pass
# it all arguments as an array.
& $exe $exeArgs

[1] Invoke-Expression следует обычно избегать, как указывает Билл, потому чтоон представляет угрозу безопасности, и есть обычно более безопасные и более надежные варианты .Здесь, однако, нет простой альтернативы, и риск безопасности устраняется путем временного замены всех экземпляров $ во входной строке, чтобы предотвратить непреднамеренную интерполяцию строки.

0 голосов
/ 22 мая 2018

Вы писали:

$var = '"C:\Program Files (x86)\Opera\Launcher.exe" /uninstall'
& $var

Вы заметили, что это не работает.Это связано с тем, что аргументом оператора & является строка, представляющая команду для выполнения (но не параметры).Правильный способ написать это будет:

$var = "C:\Program Files (x86)\Opera\Launcher.exe"
& $var /uninstall

Если вы хотите прочитать строку командной строки из реестра (или где-то еще) и выполнить ее как есть, один из способов избежать Invoke-Expression иливызов cmd.exe должен токенизировать строку.Вот функция, которая делает это:

function Split-String {
  param(
    [String] $inputString
  )
  [Regex]::Matches($inputString, '("[^"]+")|(\S+)') | ForEach-Object {
    if ( $_.Groups[1].Success ) {
      $_.Groups[1].Value
    }
    else {
      $_.Groups[2].Value
    }
  }
}

Первый элемент в возвращаемом массиве - это имя исполняемого файла, а остальные элементы (если есть) - это параметры исполняемого файла.Кавычки вокруг элементов массива сохраняются.

Вы можете использовать функцию для запуска исполняемого файла, используя оператор & следующим образом:

$var = '"C:\Program Files (x86)\Opera\Launcher.exe" /uninstall'
$tokens = @(Split-String $var)
$command = $tokens[0] -replace '^"?([^"]+)"?$', '$1'
if ( $tokens.Count -eq 1 ) {
  & $command
}
else {
  & $command $tokens[1..$($tokens.Count - 1)]
}

Третья строка в коде удаляетначальные и конечные символы " в имени команды.

Если вы хотите запустить исполняемый файл асинхронно, вы можете использовать Start-Process.Пример:

$var = '"C:\Program Files (x86)\Opera\Launcher.exe" /uninstall'
$tokens = @(Split-String $var)
$startArgs = @{
  "FilePath" = $tokens[0] -replace '^"?([^"]+)"?$', '$1'
}
if ( $tokens.Count -gt 1 ) {
  $startArgs.ArgumentList = $tokens[1..($tokens.Count - 1)]
}
Start-Process @startArgs
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...