system.Diagnostics.Process Problem

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hello,

I am attempting to start a cmd.exe process and pass several .vbs scripts
(with additional parameters) and then read the output from the scripts and
make "notes" in a DataTable (the "notes" not being the issue).

Beginning with...

Dim objProcess As Process
Dim objProcessStartInfo As New ProcessStartInfo

objProcessStartInfo.FileName =
System.Environment.GetEnvironmentVariable("ComSpec")
objProcessStartInfo.WorkingDirectory =
System.Environment.GetEnvironmentVariable("SystemRoot")
objProcessStartInfo.RedirectStandardOutput = True
objProcessStartInfo.RedirectStandardInput = True
objProcessStartInfo.RedirectStandardError = True
objProcessStartInfo.UseShellExecute = False
objProcessStartInfo.WindowStyle = ProcessWindowStyle.Normal
objProcess = Process.Start(objProcessStartInfo)

I then loop through a DataTable, attempting to fire off VBScripts (or
Batch/EXE)(a.k.a. strApplicationAction) using:
objProcess.StandardInput.WriteLine(strApplicationAction)
Ex. strApplicationAction = "C:\Scratch\CopyFile.vbs MyComputer"

then attempt to read the output from the VBScript using
objProcess.StandardOutput. I have tried all of the following:

' Problem: EndOfStream is not reached when VBScript ends only when cmd.exe
closes.
Do While (objProcess.StandardOutput.EndOfStream = False)
strOutput &= objProcess.StandardOutput.ReadLine & vbCrLf
Loop

' Problem: Hangs because it is looking for the exit of the cmd.exe
strOutput = objProcess.StandardOutput.ReadToEnd

' If condition not reached until cmd.exe is closed
Do While (objProcess.StandardOutput.EndOfStream = False)
strTemp &= objProcess.StandardOutput.ReadLine
if (strTemp = System.Environment.GetEnvironmentVariable("SystemRoot") &
">") then exit do
Loop

Note: I can collect the StandardOutput. I am just getting tripped up on
knowing when the cmd.exe is idle. What I am looking for is the ability to
determine if the cmd.exe is finished processing the first VBScript/Batch/EXE
and then fire another one using
objProcess.StandardInput.WriteLine(strApplicationAction) without having to
launch a new cmd.exe for each ApplicationAction (I already have that working
~ 100 scripts = 100 cmd.exe (or cscript.exe)). Is it even possible to read
the status of cmd.exe? Do I need to use StandardError somehow? I have
already tried WaitForInputIdle (GUI only).

Thanks in advance.
 
I have noticed that when applications such as cscript % are executing the
title of CMD changes to somthing like

"C:\windows\system32\cmd.exe - Cscript AD_addNew.vbs"

then... once finished it changes back to

"C:\windows\system32\cmd.exe"

If you use sendmessage(hwnd, WM_GETTEXT, param, param)

You could read the CMD's caption.

infact I seem to remember the Process class has a method that reads the
caption of the main window of an application.

Mike.
 
Hello Mike,

Thanks for you response. Yes, I've seen that as well (happens with any
command sent to the cmd.exe) but I am not clear on your response. Why do I
need to read the CMD's caption? I looked up sendmessage and was unable to
determine the route that you are suggesting. I have an open connection the
process, I just need to be able to identify when the cmd.exe has finished
processing the previous command that was sent so that I may send another one.

Thank you
 
Dim consoleApp As New Process

With consoleApp

..StartInfo.UseShellExecute = False

..StartInfo.RedirectStandardOutput = True

..StartInfo.FileName = "cmd"

..StartInfo.RedirectStandardInput = True

..Start()

..WaitForExit(1)

End With

'Wait for the command window to load

Threading.Thread.Sleep(500)

Do

Me.Text = (consoleApp.MainWindowTitle.ToString)

Application.DoEvents()

Loop Until consoleApp.MainWindowTitle.ToString.Length <> 0

Application.DoEvents()

consoleApp.StandardInput.WriteLine("echo off")

Application.DoEvents()

consoleApp.StandardInput.WriteLine("cls")

Application.DoEvents()

consoleApp.StandardInput.WriteLine("ipconfig /DisplayDns")



Do

Application.DoEvents()

Me.Text = ("waiting for ipcfg to complete")

Loop Until consoleApp.MainWindowTitle.ToString.EndsWith("cmd.exe")

Me.Text = "ip cfg completed"
 
Hello Mike,

That's just plain slick. As an FYI, I also needed to capture the output and
parse it and threw in a time out in case it hangs. So I thought I would post
back what I did.

Select Case True
<Several cases to set things up>
Case else
objDateTime = DateTime.Now
objProcess.StandardInput.WriteLine(strApplicationAction)
Do
System.Windows.Forms.Application.DoEvents()
If (DateDiff(DateInterval.Minute, objDateTime, DateTime.Now) > 10) Then
Exit Select
Loop Until (objProcess.MainWindowTitle.ToString.EndsWith("cmd.exe") = True)
objProcess.StandardInput.WriteLine("Done!")
objDateTime = DateTime.Now
Do
strOutput &= objProcess.StandardOutput.ReadLine & vbCrLf
If (DateDiff(DateInterval.Second, objDateTime, DateTime.Now) > 5) Then
Exit Select
Loop Until (InStr(strOutput, "Done!") > 0)

Thanks again!
Gregory
 
No problem.

Mike.
gmyers said:
Hello Mike,

That's just plain slick. As an FYI, I also needed to capture the output
and
parse it and threw in a time out in case it hangs. So I thought I would
post
back what I did.

Select Case True
<Several cases to set things up>
Case else
objDateTime = DateTime.Now
objProcess.StandardInput.WriteLine(strApplicationAction)
Do
System.Windows.Forms.Application.DoEvents()
If (DateDiff(DateInterval.Minute, objDateTime, DateTime.Now) > 10) Then
Exit Select
Loop Until (objProcess.MainWindowTitle.ToString.EndsWith("cmd.exe") =
True)
objProcess.StandardInput.WriteLine("Done!")
objDateTime = DateTime.Now
Do
strOutput &= objProcess.StandardOutput.ReadLine & vbCrLf
If (DateDiff(DateInterval.Second, objDateTime, DateTime.Now) > 5) Then
Exit Select
Loop Until (InStr(strOutput, "Done!") > 0)

Thanks again!
Gregory
 
Back
Top