I'm not sure, but I think you want to be able to send script input and receive output from another program, where the other program has a "state", which should be a script capable of interacting. The following is an example script that manages CMD.EXE. CMD has a state, such as the current working directory and environment variables.
Please note that you could do what the other responder suggested, and just run the program, give all the input on the command line, and then do what you need with the output. However, for CMD, if you need to make decisions based on output, and then provide CMD with more input based on previous output, you will have to save and restore the environment and current working directories between each time you execute CMD. The approach below does not require this.
However, the approach below has a few caveats. At first it depends on the PS host. It works (for me) on the PS command line, but not on ISE. This dependency is related to using the Raw host interface to determine if a key is available. Secondly, it depends on the time, depending on the behavior of the CMD (or what you use instead). You will see several sleep commands in the script. I had to experiment a lot so that this script displays the CMD output for a particular subcommand when entering this command, and the CMD returns the output of previous commands after another command was entered. Comment on the dream to understand what I mean. Thirdly, it is easy to hang Powershell. Killing CMD in the task manager makes you freeze, which I had to do many times.
You will see that I have added several commands that the script deals with. This means that the input to the command can come from a PS script (compared to keyboard input).
$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 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)
source share