如何在PowerShell的另一个应用程序窗口中运行交互式命令

时间:2013-06-20 04:07:19

标签: powershell powershell-v2.0 powershell-remoting

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

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

e.g。 app.exe -help调用app.exe的帮助命令。

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

2 个答案:

答案 0 :(得分:2)

试试这个:

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

使用此测试并按预期工作:

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

从扩展说明中,您似乎希望在同一命令提示符下运行2个命令。这是可能的,但是,我不确定它会在你的场景中有效。例如:

test1.bat: echo "hello!"

test2.bat:echo "goodbye!"

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

输出:

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

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

希望这有帮助。

答案 1 :(得分:0)

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

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

然而,下面的方法确实有几点需要注意。首先,它取决于PS“主机”。它在命令行PS上工作(对我来说),但不在ISE中。此依赖性是由于使用Raw主机接口来确定密钥是否可用。其次,它取决于时间,基于CMD的行为(或者你使用的任何东西)。您将在脚本中看到一些睡眠命令。我必须尝试一个整个批次来让这个脚本在输入该命令时显示特定子命令的CMD输出,而CMD在输入另一个命令后给出先前命令的输出。注释睡眠,看看我的意思。第三,很容易挂起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)