Link to home
Start Free TrialLog in
Avatar of sirbounty
sirbountyFlag for United States of America

asked on

redirecting output...all of it...

I found this method on another site (see http://www.devx.com/dotnet/Article/7914/0/page/5)

I've also attempted doing this using the process arguments - I can't get the results I'm after.

My goal is to shell a psexec (PSTools from Sysinternals) to another server to retrieve a list of policies in use by the quota management product.

Normally, this is accomplished via:

psexec \\server sesrm /list

The output produces approx. 300 lines of policies.

The closest I can get is the 'title' information and maybe the first policy.

Anyone willing to help me out? :^)
Avatar of oleggold
oleggold
Flag of United States of America image

May be there's a problem with the Sysinternals to give it in alist  and You should use VB script :
http://www.microsoft.com/technet/isa/2004/plan/creatingpolicyrulereports.mspx
Avatar of sirbounty

ASKER

Not sure what you mean by that?

I can run psexec from a command line (cmd) with no problem - and it produces the output as expected.

If I try running a process with either cmd or psexec in .net, it fails to produce anything beyond the first 3-4 lines.

I don't see how the link fits in here..?
Hi sirbounty;

Have you tried it this way?

        Dim myProcess As Process = New Process()
        Dim s As String

        ' Give full path and filename here     <===========
        myProcess.StartInfo.FileName = "C:\Program Files\SysInternals\PsTools\psexec"

        myProcess.StartInfo.Arguments = "\\server sesrm /list"
        myProcess.StartInfo.UseShellExecute = False
        myProcess.StartInfo.CreateNoWindow = True
        myProcess.StartInfo.RedirectStandardOutput = True
        myProcess.Start()

        Dim sOut As StreamReader = myProcess.StandardOutput
        myProcess.WaitForExit()

        s = sOut.ReadToEnd()

        MessageBox.Show(s)

        sOut.Close()
        myProcess.Close()

Fernando
Hi Fernando - I'll give it a try, but let me say, if I do not include any parameters/arguements, I get "plenty" of output (basically PSExec's 'usage') which is about 3 pages worth...the code I use for that is:
(psexec, on my system, is in the path, cause I've dropped it in system32).

        Dim ps As Process = Nothing
        Dim psNfo As New ProcessStartInfo

        With psNfo
            .RedirectStandardOutput = True
            .UseShellExecute = False
            .FileName = "psexec.exe"
        End With

        Dim myPS As System.Diagnostics.Process = System.Diagnostics.Process.Start(psNfo)
        Dim strData As String = myPS.StandardOutput.ReadToEnd()
        myPS.WaitForExit()
        myPS.Close()

        MsgBox(strData)

Granted, this runs and the output is given right from the exe - the output that I'm looking for takes a bit of a delay in that it has to pass the application (sesrm.exe) to the server, which takes a bit to generate a report.

My thinking was that maybe it wasn't given enough time/delay to gather the entire output - but I see no way of waiting for it to complete, cause the 'hasexited' property is true, even though I only have the 1st 4 lines of the 300 or so lines of output.

I found something a bit ago that suggested multiple threads be issued - one to process the command another to receive the results - but it was in c, and I don't know c...
Hi sirbounty;

Try your code then with this order, change the WaitForExit with the ReadToEnd as shown below.

        Dim myPS As System.Diagnostics.Process = System.Diagnostics.Process.Start(psNfo)
        myPS.WaitForExit()
        Dim strData As String = myPS.StandardOutput.ReadToEnd()
        myPS.Close()


Fernando
By itself - that displays psexec's usage.
If I add the
\\server sesrm /list
as the startinfo's arguments,
I get a pop-up command window whose title changes from
C:\winnt\system32\psexec.exe
to
\\server: sesrm /list

but strData is empty (even though it probably paused long enough to gather the output).
Can you post the code that gave you the results shown below.

I get a pop-up command window whose title changes from
C:\winnt\system32\psexec.exe
to
\\server: sesrm /list
It's just your 'adjustment' above with the added

With psNfo
 [...]
 .Arguments="\\server sesrm /list"
End With
You say that this code will produce, 1st 4 lines of the 300 or so lines of output,

        Dim ps As Process = Nothing
        Dim psNfo As New ProcessStartInfo

        With psNfo
            .RedirectStandardOutput = True
            .UseShellExecute = False
            .FileName = "psexec.exe"
        End With

        Dim myPS As System.Diagnostics.Process = System.Diagnostics.Process.Start(psNfo)
        Dim strData As String = myPS.StandardOutput.ReadToEnd()
        myPS.WaitForExit()
        myPS.Close()

        MsgBox(strData)

But the code does not pass any of the arguments to psexec?
Have you tried the above code with the change I asked you to make see below.?

        Dim ps As Process = Nothing
        Dim psNfo As New ProcessStartInfo

        With psNfo
            .RedirectStandardOutput = True
            .UseShellExecute = False
            .FileName = "psexec.exe"
        End With

        Dim myPS As System.Diagnostics.Process = System.Diagnostics.Process.Start(psNfo)
        myPS.WaitForExit()
        Dim strData As String = myPS.StandardOutput.ReadToEnd()
        myPS.Close()

        MsgBox(strData)

Hi sirbounty;

Have you run the command from the DOS prompt/ Command Window? If you are transfering the program sesrm to the remote system then the arguments should look like \\server -c sesrm /list

Fernando
What's the -c for?
Both these versions shows a msgbox that's as tall as the screen....with the 'usage' of psexec.

Both show a 'blank' strData if I add the arguments.
Thought just occurred to me though, that maybe I should be passing the path of sesrm --trying now..

The -c option

-c
 Copy the specified program to the remote system for execution. If you omit this option then the application must be in the system's path on the remote system.
 
Oh - that's psexec's argument - well, it is in the path, but even specifying it produces the same results...
I think I may test with something else - like maybe running notepad from the server using psexec or something that will produce output of some sort...probably the sesrm that's causing the problem - but I know 'some' combination before (of which I can't point a finger to precisely at the moment) 'worked' in that it captured the first 4 lines...

Another site I'd seen suggested the dual-threads where one utilized a 'readline' loop, as opposed to a readtoend - not sure if that's helpful - I couldn't produce anything further from it...
-c didn't do it either...<sigh>...
To your question, "Another site I'd seen suggested the dual-threads where one utilized a 'readline' loop, as opposed to a readtoend - not sure if that's helpful - I couldn't produce anything further from it..."

This is so that StanderdError and StanderdOutput do not cause a deadlock condition trying to caspture output. This is not an issue here because you are only accessing the StandardOutput and the program does not hang.

Have you tried running the command psexec \\server sesrm /list from a DOS window to see what kind of output you would get?
"psexec \\server sesrm /list"

Yes - from a command prompt works perfectly - though there's about 3 second lag before it produces the output...
When you run it from the command prompt, does it open a new DOS window and displays the output there?
Nope.
Click Start->Run->CMD <Enter>
Type psexec \\server sesrm /list
works...as does
Start->Run->psexec \\server sesrm /list (though the window disappears when it's done...

Start->Run->cmd /c psexec \\server sesrm /list
works but leaves the cmd window open...
Start->Run->cmd /c psexec \\server sesrm /list
works but leaves the cmd window open...

But a second Command windows does not open where it displays the data? Or is the data displayed in the original Command window?
Changed to 'this':

          .FileName = "psexec.exe"
            .Arguments = " -c server cmd /c dir c:\"

only shows the volume label - doesn't produce any file listing in the output (strData)
Ok - took the code from here: http://vb-helper.com/howto_net_run_dos.html

and this is what I find...

Using cmd.exe as the file and args of "dir c:\"
returns:

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\<path to my application\bin\Debug>

and that's it  Even though I pointed it to dir of C:\ (root)

so, passing it through a shell using cmd as the filename and a
/c dir c:\

produces exactly what I'd expect - the full root listing...

Changing the filename to psexec and the args to
\\server cmd /c dir c:\

returns 'only' the volume label and serial number - no files.

Exact same results if the filename is cmd, and the args are
/c \\server cmd /c dir c:\
using cmd.exe as the filename
and arguments of:

/c c:\winnt\system32\psexec.exe \\server cmd /c dir c:\

gives volume and serial # to sOut, but the following to sErr:


PsExec v1.59 - Execute processes remotely
Copyright (C) 2001-2005 Mark Russinovich
Sysinternals - www.sysinternals.com

Connecting to server...
Starting PsExec service on server...
Connecting with PsExec service on server...
Starting cmd on server...
 cmd exited on server with error code 0.

But, I don't see anything further...weird.  I'm stumped - hoping you have something else to try...
Current code (that produces the first 3-4 lines):

 Dim start_info As New ProcessStartInfo("cmd.exe")
 start_info.UseShellExecute = False
 start_info.CreateNoWindow = False
 start_info.RedirectStandardOutput = True
 start_info.RedirectStandardError = True
 start_info.RedirectStandardInput = True
 
 ' Make the process and set its start information.
 Dim proc As New Process()
 proc.StartInfo = start_info

 ' Start the process.
 proc.Start()

 Dim sIn As System.IO.StreamWriter = proc.StandardInput
 sIn.AutoFlush = True

 ' Attach to stdout and stderr.
 Dim std_out As StreamReader = proc.StandardOutput()
 Dim std_err As StreamReader = proc.StandardError()

 sIn.Write("psexec \\server sesrm /list > pol.txt" & System.Environment.NewLine)
 sIn.Write("exit" & System.Environment.NewLine)

 Dim sOut As String = std_out.ReadToEnd()
 Dim sErr As String = std_err.ReadToEnd()

 If Not proc.HasExited Then
  proc.Kill()
 End If

This produces the output file pol.txt which contains

Policies that can be used on machine \\Server:

First Policy description

...but there are a couple hundred more...where'd they go?  :-o
Maybe this helps you...I'll keep playing and hopefully come up with something....

I put a bogus loop between these two lines:

sIn.Write("psexec \\server sesrm /list > pol.txt" & System.Environment.NewLine)
 do
 loop until proc.hasexited
sIn.Write("exit" & System.Environment.NewLine)

When I stopped the loop and allowed the 'exit' to commit, I had 191 lines of output in my array using:
Dim s() As String = Split(std_out.ReadToEnd, vbNewLine)

So...close....
This "works" - but it's a hack...

       sIn.Write("psexec \\server sesrm /list" & System.Environment.NewLine)
        Dim x As Short
        Do
            x += 1
        Loop Until x = 15000 'at 10000, it still only produces 10 lines off output - and even at 15000, it fails sometimes... :|
        sIn.Write("exit" & System.Environment.NewLine)

        Dim s() As String = Split(std_out.ReadToEnd, vbNewLine)

        Dim sErr As String = std_err.ReadToEnd()

What other option(s) do I have?
I don't know - crud - now it's not working again...
No clue what the problem could be either...I'm close to giving up - unless you have any other suggestions...
What version of Visual Basic .Net 2003 or 2005?
2005
ASKER CERTIFIED SOLUTION
Avatar of Fernando Soto
Fernando Soto
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
trying now...
I got the message "Process has exited" - but how do I view the output?
Seems to contain everything I need - but I'm not quite sure how to 'get' at it?
Hi sirbounty;

The results are in the StringBuilder variables ErrorOutput and StdOutput. In the event ProcessExited you can do what you need to do with them. To access the values in the ErrorOutput and StdOutput just use the ToString method.

    Dim errStr As String = ErrorOutput.ToString()
    Dim stdStr As String = StdOutput.ToString()

Or something like this:

    MessageBox.Show(StdOutput.ToString())

Fernando
Other than some name changes, I'm using your code, yet when the process exits, I get a blank msgbox...
I'll keep playing with it - but if you have any ideas, let me know.  Thanx.
I have notices that they do write to the error output stream so print both string builder variables to check for output.
I do get the error output in the msgbox - indicating that psexec exited with a code of 0.
But looking at it further - the end of that data has:

Run-time exception thrown : System.Configuration.ConfigurationErrorsException - The configuration section cannot contain a CDATA or text element. (<PathtoApp>.vshost.exe.config line 22)
Hold one - 'appears' to be working, but I've no clue what changed...weird... (and it's in the stdout)
They use StandardOut to send progrm output and StandardError to send error messages.
I can't seem to get consistent results - not sure how I saw it that one time...

I'm using this:

 Dim strRslt As String = sbStdOut.ToString
 MessageBox.Show(strRslt)

I know it was the stdout where I saw the data I needed before..
It seems that 'most' of the time I run this, I get a blank msgbox - I've now seen the results I need only twice using this method.  I'm starting to wonder if maybe I shouldn't spawn a process that writes the stupid output to a text file and then read that in...this is indeed frustrating...

It's difficult too, because when I try to debug it, and print the strRslt, I get all those exceptions... :(
Did you investigate what is on line 22 of this file ApplicationName.vshost.exe.config. This file is located in the bin/debug directory of the project folder XML plain text file?
Yeah - don't know how it got there - it was an added
-->
that I removed.
I think that's it for this piece - I'd like to test it a bit more to make sure it's consistent.
Thanx for all your help.

I may post another Q shortly to filter out the data that I need from this output... :)
I'm going to try to increaes the timeout on psexec (I believe there's a paramter for that) - it's still about 50% failing...
This is the only time out defined for that program. But if you are getting only half the data then this is most likely not an issue seeming it is already connected.

-n  Specifies timeout in seconds connecting to remote computers.

 
I just don't know why it's dropping it sometimes.
I'll run it - plug in a sharename and get an empty msgbox.
If I run it again, I may get another empty msgbox, or I might get the data I'm wanting - sometimes I might get my data twice in a row.  I'm not sure what's hanging it up - I increased the timeout for psexec to 600 seconds...but it doesn't seem to have helped.

Any ideas how to troubleshoot this?  I know you've really been at this as long as I have, so I understand if you're tired of dealing with this one.  I do appreciate your time and willingness to help - thanx again.
Try running the program you are developing from outside of visual studio IDE using Windows Explorer. I have come accres times when a program would work outside the VS IDE and when run from with in the IDE it would fail.
You mean compile it and then run it?
I can try that...
i ran the exe from the bin\release folder and it displayed an empty msgbox 3 for 3 attempts... :(
Hi sirbounty;

I went to the SysInternals web site and did a search on Psexec and in one of the post I found this posted by one of the Group Moderator Karl, "In particular, redirecting stdin, stdout, stderr seems to be an issue, because it seems to be in conflict with the named pipes used by psexec/psexesvc (local/remote) to handle stdin/stdout/stderr. (Karl )"  Karl also states, "I.e you will get lots of reports, and quite a number of them will report on issues running psexec from inside an application (other than cmd.exe), but hardly any offering a solution. ", he was talking about searching the PSTools Forum. I believe that what you have been trying to do has been a known issue and one they have not been addressing.

Link to the post:
    http://forum.sysinternals.com/forum_posts.asp?TID=6655&KW=psexec

Fernando
I will start testing with that beyondexec that is mentioned in there...thanx
Thanx for all your time and effort on this...
I think I'm going to take it another direction.
Not a problem, glad I was able to help some how. ;=)
Maybe you can help me with this!
I just stumbled upon a tlb (typelibrary) file?
I don't know much about it - but opening it with .Net reveals all the commands that I need...
If you have any familiarity with this, let me know and I'll post the Q # here when I get it posted...
Native dll code. Can you tell me the name of the file?
It's qasvr.tlb - it's part of Storage Exec (previously Storage Central) - by Veritas...
Where did you find the file?
Can't find any reference to this file anywhere? Where did you find it?
It's included with Veritas Storage Exec (now Symantec, I believe)
Can I send it to you?
You can post it to the EE web site at http://www.ee-stuff.com/login.php Login to it like you do here, same username and password as here. Then click on the Expert area tab and follow instructions to upload files to a question.