5

我有另一个命令行程序,我从我的 powershell 脚本中调用它,并且希望在从 power shell 打开后在该窗口中运行一些交互式命令。

换句话说 - 我做了一个Invoke-Item $link_to_app为该应用程序打开交互式命令行的操作,现在我想在 powershell 脚本中使用应用程序特定的命令。

例如app.exe -help调用app.exe.

任何指针都会有所帮助。谢谢!

4

2 回答 2

2

尝试这个:

$app = 'app.exe -help'
Invoke-Expression $app

对此进行了测试,它按预期工作:

$pingTest = 'ping -n 8 127.0.0.1'
Invoke-Expression $pingTest

从您的扩展说明中,您似乎想要在同一命令提示符下运行 2 个命令。这是可能的,但是,我不确定它是否适用于您的场景。例如:

测试1.bat: echo "hello!"

测试2.bat:echo "goodbye!"

$batchTest = "test1.bat && test2.bat"
cmd /c $batchTest 

输出:

D:\Test>echo "hello!"
"hello!"

D:\Test>echo "goodbye!"
"goodbye!"

希望这可以帮助。

于 2013-06-20T05:14:58.693 回答
1

我不确定,但我认为您想要的是让脚本向另一个程序发送输入并从另一个程序接收输出的能力,其中另一个程序具有您的脚本需要能够与之交互的“状态”。下面是一个驱动 CMD.EXE 的脚本示例。CMD 有状态,例如当前工作目录和环境变量。

请注意,您可以按照其他回答者的建议进行操作,然后启动程序,在命令行上提供所有输入,然后对输出执行您需要的操作。但是对于 CMD,如果您需要根据输出做出决策,然后根据先前的输出为 CMD 提供更多输入,则必须在每次执行 CMD 之间保存和恢复环境和当前工作目录。下面的方法不需要这样做。

然而,下面的方法确实有几个警告。首先它依赖于PS“主机”。它在命令行 PS 上(对我来说)有效,但在 ISE 中无效。这种依赖性是由于使用原始主机接口来确定密钥是否可用。其次,它取决于时间,基于 CMD 的行为(或您使用的任何东西)。您将在脚本中看到一些睡眠命令。我必须进行大量试验才能让这个脚本在输入该命令时显示 CMD 对特定子命令的输出,而 CMD 在输入另一个命令后给出先前命令的输出。注释掉 sleeps 看看我的意思。三是容易挂Powershell。在任务管理器中杀死 CMD 可以让你摆脱挂起状态,我不得不这样做很多次。

您会看到我添加了几个脚本专门处理的命令。这是为了证明命令的输入可以来自 PS 脚本(而不是来自键盘的输入)。

$global:ver++
if ($ExecutionContext.Host.name -match "ISE Host$") {
    write-warning "This script relies on RawUI functionality not implemented in ISE"
    return
}
$in = $null
$flExiting = $false

$doDebug = $false
function dot-debug {param($color) 
  if ($doDebug) {
    write-host "." -NoNewline -ForegroundColor $color
  }
}
#function dot-debug {param($color) }

$procInfo = new diagnostics.processstartinfo
$procInfo.RedirectStandardOutput=1
$procInfo.RedirectStandardInput=1
$procInfo.RedirectStandardError=1
$procInfo.FileName="cmd.exe"
$procInfo.UseShellExecute=0
$p=[diagnostics.process]::start($procInfo)
$outBuf = new char[] 4096
write-host "Version $ver"
sleep -Milliseconds 300
do {
   dot-debug red

  # This while loop determines whether input is available from either
  #  CMD's standard output or from the user typing. You don't want to
  #  get stuck waiting for input from either one if it doesn't really have input.

  :WaitIO  while ($true) {
    if (-1 -ne $p.StandardOutput.peek()) {
      dot-debug yellow
      $cnt = $p.StandardOutput.read( $outBuf, 0, 4096)
    } else {
      dot-debug Gray
      if ($host.ui.rawui.KeyAvailable -or $flExiting) {break}
    }
    $str = $outBuf[0..($cnt-1)] -join ""
    write-host "$str" -NoNewline

    while (-1 -eq ($rc =$p.StandardOutput.peek())) {
      if ($host.ui.rawui.KeyAvailable -or $flExiting) {
        break WaitIO
      }
      dot-debug DarkGray
      sleep -milli 200
    }
    dot-debug cyan
  }
  dot-debug green

  # read-host echoes input, so commands get echoed twice (cmd also echoes)
  #
  # $host.ui.rawui.ReadKey("NoEcho, IncludeKeyDown") doesn't work on ISE,
  # but does work in the PS cli shell
  if ($in -ne "exit") {$in = read-host}
  if ($in -eq "td") { # toggle debug
    $doDebug = -not $doDebug
    $p.StandardInput.WriteLine( "echo debug toggled")
    sleep -milli 300
    continue
  }
  if ($in -eq "xxx") {
    # Example of script driven output being sent to CMD
    $p.StandardInput.WriteLine( "echo This is a very long command that I do not want to have to type in everytime I want to use it")
    # You have to give CMD enough time to process command before you read stdout,
    # otherwise stdout gets "stuck" until the next time you write to stdin
    sleep -milli 1
    continue
  }
  if ($in -eq "exit") {
    $flExiting = $true
    $p.StandardInput.WriteLine($in)
    continue
  }

  foreach ($char in [char[]]$in) {
    $p.StandardInput.Write($char)
  }
  $p.StandardInput.Write("`n")
  sleep -milli 1

} until ($p.StandardOutput.EndOfStream)
于 2013-06-22T19:17:35.930 回答