tags:

views:

672

answers:

3

Hi, so I've tried Process and starting a cmd.exe and send commands directly to that window. And then picking up the values written to the cmd.exe window.

The code looks like this:

Dim arrServers As ArrayList
    Dim s(ListBoxServers.Items.Count) As String

    ListBoxServers.Items.CopyTo(s, 0)
    arrServers = New ArrayList(s)

    Using P As New Process
        P.StartInfo.FileName = "cmd.exe"
        P.StartInfo.UseShellExecute = False
        P.StartInfo.RedirectStandardOutput = True
        P.StartInfo.RedirectStandardInput = True
        P.Start()
        For Each i In arrServers
            P.StandardInput.WriteLine("query user " & txtBoxUsername.Text & " /server:" & i)
        Next
        P.StandardInput.WriteLine("exit")
        Output = P.StandardOutput.ReadToEnd()
        Trace.WriteLine(Output)
        MsgBox(Output)
        P.WaitForExit()

    End Using

But is looks like it doesn't "press enter" or something. Meaning, I don't get any results from the command. I don't even get a "'command' is not recognized as an internal or external command, operable program or batch file." like you normally get if it doesn't understand the syntax.

+2  A: 

Look into the Process class in the System.Diagnostics namespace for running your batch file.

Tim
Do be sure to mention ProcessStartInfo.RedirectStandardOutput to make your answer complete.
Hans Passant
+1  A: 

Use a library/class like NDesk's Options for flexible argument handling. If you don't want to use a external component, you'll have to loop over the arguments and process them manually:

For Each arg As String In Environment.GetCommandLineArgs()
  Select Case arg
    Case "/blah"
      ' process /blah '
    Case "/foo"
      ' process foo '
    Case Else
      MsgBox "Unknown argument " + arg " found, aborting.", vbCritical
      Environment.Exit(1)
  End Select
Next

[I normally don't do VB, so this is just an untested sketch]

David Schmitt
A: 

Imagine the following really simple batch file called "hello.bat"

@ECHO OFF
echo Hello

You can call it and see "Hello" by using:

    'Will hold the results of the batch
    Dim Output As String
    'Create a new process object
    Using P As New Process()
        'Set the script to run
        P.StartInfo.FileName = "c:\scripts\hello.bat"
        'My script doesn't take argument but this is where you would pass them
        P.StartInfo.Arguments = ""
        'Required to redirect output, don't both worrying what it means
        P.StartInfo.UseShellExecute = False
        'Tell the system that you want to see the output
        P.StartInfo.RedirectStandardOutput = True
        'Start your batch
        P.Start()
        'Read the entire contents of the outout
        Output = P.StandardOutput.ReadToEnd()
        'Wait until the batch is done running
        P.WaitForExit()
    End Using
    'Do something with the output
    Trace.WriteLine("Batch produced : " & Output)

Edit

Here's a version that doesn't run a batch but instead runs a couple of standard commands. We start by firing up a command shell to pass things to. One thing that sucks is that its hard to run a command, read the output and then run another command. The code below runs two commands back-to-back and dumps the entire result into a string. If you have a need for running a command, processing, running another command, I think you'll have to wire up something to StandardError and look at return codes. Before you do that, make sure you read up on problem with blocking and how other places solve it by wiring threads up such as here. Probably the easier way is to wrap this into a sub and call the sub once for each command.

    'Will hold all of the text
    Dim Output As String
    'Create a new process object
    Using P As New Process()
        'Set the script to run the standard command shell
        P.StartInfo.FileName = "cmd.exe"
        'Required to redirect output, don't both worrying what it means
        P.StartInfo.UseShellExecute = False
        'Tell the system that you want to read/write to it
        P.StartInfo.RedirectStandardOutput = True
        P.StartInfo.RedirectStandardInput = True
        'Start your batch
        P.Start()
        'Send your various commands
        P.StandardInput.WriteLine("dir c:\")
        P.StandardInput.WriteLine("ipconfig /all")
        'Very important, send the "exit" command otherwise STDOUT will never close the stream
        P.StandardInput.WriteLine("exit")
        'Read the entire stream
        Output = P.StandardOutput.ReadToEnd()
        'Wait until the batch is done running
        P.WaitForExit()
    End Using
    'Do something with the output
    Trace.WriteLine(Output)

Edit 2

I'm having problems with the "query user" command in general, I can't get it to return anything for usernames with spaces in them even if I enclose the name in quotes. But here's a version that uses "quser" instead which does the exact same thing as far as I know.

    'Will hold all of the text
    Dim Output As String
    'Create a new process object
    Using P As New Process()
        'Set the script to run the standard command shell
        P.StartInfo.FileName = "cmd.exe"
        'Required to redirect output, don't both worrying what it means
        P.StartInfo.UseShellExecute = False
        'Tell the system that you want to read/write to it
        P.StartInfo.RedirectStandardOutput = True
        P.StartInfo.RedirectStandardInput = True
        'Start your batch
        P.Start()
        'Send your various commands
        'Array of servers
        Dim arrServers() As String = New String() {"SERVER1", "SERVER2"}
        'Loop through array, wrap names with quotes in case they have spaces
        For Each S In arrServers
            P.StandardInput.WriteLine(String.Format("quser ""{0}"" /SERVER:{1}", Me.txtBoxUsername.Text, S))
        Next
        'Very important, send the "exit" command otherwise STDOUT will never close the stream
        P.StandardInput.WriteLine("exit")
        'Read the entire stream
        Output = P.StandardOutput.ReadToEnd()
        'Wait until the batch is done running
        P.WaitForExit()
    End Using
    'Do something with the output
    Trace.WriteLine(Output)
Chris Haas
Btw, I updated the OP code. But it doesn't really seem to work. I mean, I can write "ipconfig" and show the results in a string og messagebox. And that's fine. But somehow, the command "query user" doesn't really give an output. All I can see is the command I send to the cmd window.
Kenny Bones
Hmm, the same thing happens. Weird thing though, if I send an input command which looks like "hahaha" or something, I get the same results. No results in other words. I would expect to get "syntax error" or something. Just like I would get if i started cmd.exe manually and typed "hahaha"
Kenny Bones
If you run the code exactly as is above does it work? I'm using Trace.WriteLine above which writes to whatever's configured as a trace output which in the IDE is the Immediate Window, are you sure nothing's going there? Maybe MsgBox the results instead? Don't know what else to tell you otherwise.
Chris Haas
Yes, I do use a MsgBox to output the results. But it's like the commands themselves don't give any output. This is an image of the direct output. http://img4.imageshack.us/img4/1076/outputn.jpgIf I type the exact same string in a cmd window manually, I clearly get a result from it.
Kenny Bones
Maybe try calling ECHO ON as the first command, I can't think of anything else that would cause this
Chris Haas