在Powershell中从变量执行“真实生活”命令行

时间:2018-05-22 16:47:29

标签: powershell

例如,当我从注册表中读取一些卸载字符串时,如"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 :(得分:1)

您写道:

$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

答案 1 :(得分:1)

我认为比尔斯图尔特的答案是正确的做法。如果由于某种原因你无法得到比尔的工作答案,你可以使用Invoke-Expression来做到这一点。

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

答案 2 :(得分:1)

要使用 Original New A B C | D E F G 50 30 50 | None None 50 None 10 10 10 | 10 10 10 10 30 20 20 | None None None 20 20 20 20 | 20 20 20 20 70 50 70 | None None 70 None (如果命令名称/路径是不带引号的文字,请直接调用),请 命令名称/路径必须从其自变量中单独传递
调用外部程序时,您可以将这些参数作为 array 传递。

下面的解决方案利用PowerShell自己的& cmdlet结合安全调用Write-Output [1]  以便将字符串解析为其组成参数。

Invoke-Expression

[1] Invoke-Expression should generally be avoided, as Bill points out, because it presents a security risk and there are typically safer and more robust options available。但是,这里没有简单的替代方法,并且临时替换输入字符串中的所有# 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 实例以防止意外的字符串插值可以避免安全风险。 < / p>