Solved

Parse the output of DOS command

Posted on 2009-05-12
14
675 Views
Last Modified: 2012-05-06
Hello,

I have a console (vb.net) program in which I am opening a DOS prompt and running the PSINFO command:
:\PSINFO "Kernel version" \\computername>
What I need is to pick up only the machine's OS from the results that this command brings back.  The below is what the PSINFO output looks like.  I need to pluck out only the part that has the OS version info.  From the below example it would be "Microsoft Windows Server 2003, Multiprocessor Free".  I have done all kinds of string manipulations, but haven't succeeded in picking out just the OS version.  I hope someone can help me.:
====================================================
C:\GARTDiscoverServerOS>psinfo "Kernel version" \\entlc201

PsInfo v1.75 - Local and remote system information viewer
Copyright (C) 2001-2007 Mark Russinovich
Sysinternals - www.sysinternals.com

System information for \\entlc201:
Kernel version:            Microsoft Windows Server 2003, Multiprocessor Free


C:\GARTDiscoverServerOS>
=======================================================
Function GetOSVersionThruPSINFO(ByVal strServerIP As String, ByVal strDomain As String) As String

        Dim myProcess As New System.Diagnostics.Process

        Dim s, serverOS As String

        Dim startlocation, endlocation As Integer
 

        Try

            ''''''' Starting DOS Prompt

            myProcess.StartInfo.FileName = "cmd.exe"

            myProcess.StartInfo.UseShellExecute = False

            myProcess.StartInfo.CreateNoWindow = True

            myProcess.StartInfo.RedirectStandardInput = True

            myProcess.StartInfo.RedirectStandardOutput = True

            myProcess.StartInfo.RedirectStandardError = True
 

            myProcess.Start()
 

            Dim sIn As StreamWriter = myProcess.StandardInput

            Dim sOut As StreamReader = myProcess.StandardOutput

            Dim sErr As StreamReader = myProcess.StandardError
 

            sIn.AutoFlush = True
 

            log.Info("*******************Now performing PSINFO for Incoming Server Name: " & strDomain & " - " & strServerIP)

            ''''''' This command filters everything else out....except for what I need which is the Kernal version

            sIn.Write("psinfo ""Kernel version"" \\" & strDomain & System.Environment.NewLine)
 

            sIn.Write("exit" & System.Environment.NewLine)
 

            '''''''' going into read mode - read the results of DOS command

            s = sOut.ReadToEnd()
 

            If Not myProcess.HasExited Then

                myProcess.Kill()

            End If
 

            sIn.Close()

            sOut.Close()

            sErr.Close()

            myProcess.Close()

            log.Info("Output of PSINFO: " & s)
 

            If s.IndexOf("Kernel version") > 1 Then

                startlocation = (s.IndexOf("Kernel version") + 27)

            End If
 

            '''''''''End If
 

            Dim intEntireLen As Integer = s.Length()

            Dim intFirstSpace As Integer = s.IndexOf(" ", startlocation)
 

            serverOS = s.Substring(startlocation, ((intFirstSpace - 1) - startlocation))
 

            Return serverOS

        Catch ex As Exception

            log.Error("Error occurred: " & ex.Message)

        End Try

    End Function

Open in new window

0
Comment
Question by:msyed1
  • 7
  • 7
14 Comments
 
LVL 21

Expert Comment

by:AmazingTech
ID: 24365665
From DOS on the command line.
for /f "tokens=2,* delims=: " %a in ('psinfo "kernel version" \\entlc201 ^| find /i "kernel version"') do echo %b

Open in new window

0
 

Author Comment

by:msyed1
ID: 24365757
AmazingTech:
I need more help then that.  Please explain what this command does and where exactly does it fit in...in my code ??  
0
 
LVL 21

Expert Comment

by:AmazingTech
ID: 24365905
Hmm...

Replace line 25 with code below.

If it works properly it should display

Output of PSINFO: Microsoft Windows Server 2003, Multiprocessor Free


     sIn.Write("for /f ""tokens=2,* delims=: "" %a in ('psinfo ""kernel version"" \\" & strDomain & " ^| find /i ""kernel version""') do echo %b" & System.Environment.NewLine)

Open in new window

0
 

Author Comment

by:msyed1
ID: 24366393
AmazingTech:
I did what you advised and still 's' which is the output of the command has all kinds of junk in it...so I will still need to parse out the OS Version, which is Microsoft Windows 2000.  All I need is machine's OS version.  Please see the attachment that shows the value of 's' in debug mode.  msyed1
debug-screen.doc
0
 
LVL 21

Expert Comment

by:AmazingTech
ID: 24366652
Oh... I see now.

There's probably 2 different ways to fix this. I really only want to get the info you want so we'll try and get it to only output what we want in sOut.ReadToEnd() instead of parsing this.


Function GetOSVersionThruPSINFO(ByVal strServerIP As String, ByVal strDomain As String) As String

        Dim myProcess As New System.Diagnostics.Process

        Dim s, serverOS As String

        Dim startlocation, endlocation As Integer

 

        Try

            ''''''' Starting DOS Prompt

            myProcess.StartInfo.FileName = "cmd.exe"

            myProcess.StartInfo.UseShellExecute = False

            myProcess.StartInfo.CreateNoWindow = True

            myProcess.StartInfo.RedirectStandardInput = True

            myProcess.StartInfo.RedirectStandardOutput = True

            myProcess.StartInfo.RedirectStandardError = True

 

            myProcess.Start()

 

            Dim sIn As StreamWriter = myProcess.StandardInput

            Dim sOut As StreamReader = myProcess.StandardOutput

            Dim sErr As StreamReader = myProcess.StandardError

 

            sIn.AutoFlush = True

 

            log.Info("*******************Now performing PSINFO for Incoming Server Name: " & strDomain & " - " & strServerIP)

            ''''''' This command filters everything else out....except for what I need which is the Kernal version

            sIn.Write("/c @for /f ""tokens=2,* delims=: "" %a in ('@psinfo ""kernel version"" \\" & strDomain & " ^| @find /i ""kernel version""') do @echo %b" & System.Environment.NewLine)

  

            '''''''' going into read mode - read the results of DOS command

            s = sOut.ReadToEnd()

 

            If Not myProcess.HasExited Then

                myProcess.Kill()

            End If

 

            sIn.Close()

            sOut.Close()

            sErr.Close()

            myProcess.Close()

            log.Info("Output of PSINFO: " & s)

 

            serverOS = "Not Available"

            if s <> "" then serverOS = s

 

            Return serverOS

        Catch ex As Exception

            log.Error("Error occurred: " & ex.Message)

        End Try

    End Function

Open in new window

0
 

Author Comment

by:msyed1
ID: 24368476
AmazingTech:  I am trying to test the latest you sent, but the  's = sOut.ReadToEnd()' takes a very LOOOONNG time.  It goes into the DOS mode at that line and stays there for hours.  Right now I am testing with only 1 servername.  Do you have any idea why the command ReadToEnd() takes so long ?? msyed1.
0
 
LVL 21

Expert Comment

by:AmazingTech
ID: 24369275
Hmm... Maybe it doesn't work properly with /c to close cmd.exe when the code is finished.

OK. Let's go back to your original code and now see if we can get the proper line.
Function GetOSVersionThruPSINFO(ByVal strServerIP As String, ByVal strDomain As String) As String

        Dim myProcess As New System.Diagnostics.Process

        Dim s, serverOS As String

        Dim startlocation, endlocation As Integer

 

        Try

            ''''''' Starting DOS Prompt

            myProcess.StartInfo.FileName = "cmd.exe"

            myProcess.StartInfo.UseShellExecute = False

            myProcess.StartInfo.CreateNoWindow = True

            myProcess.StartInfo.RedirectStandardInput = True

            myProcess.StartInfo.RedirectStandardOutput = True

            myProcess.StartInfo.RedirectStandardError = True

 

            myProcess.Start()

 

            Dim sIn As StreamWriter = myProcess.StandardInput

            Dim sOut As StreamReader = myProcess.StandardOutput

            Dim sErr As StreamReader = myProcess.StandardError

 

            sIn.AutoFlush = True

 

            log.Info("*******************Now performing PSINFO for Incoming Server Name: " & strDomain & " - " & strServerIP)

            ''''''' This command filters everything else out....except for what I need which is the Kernal version

            sIn.Write("for /f ""tokens=2,* delims=: "" %a in ('psinfo ""kernel version"" \\" & strDomain & " ^| find /i ""kernel version""') do echo %b" & System.Environment.NewLine)

            sIn.Write("exit" & System.Environment.NewLine)
 

            '''''''' going into read mode - read the results of DOS command

            s = split(sOut.ReadToEnd(), System.Environment.NewLine)

 

            If Not myProcess.HasExited Then

                myProcess.Kill()

            End If

 

            sIn.Close()

            sOut.Close()

            sErr.Close()

            myProcess.Close()

            log.Info("Output of Kernel Version: " & s(6))

 

            serverOS = "Not Available"

            if s(6) <> "" then serverOS = s(6)

 

            Return serverOS

        Catch ex As Exception

            log.Error("Error occurred: " & ex.Message)

        End Try

    End Function

Open in new window

0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 

Author Comment

by:msyed1
ID: 24369390
Now I am getting
"Value of type '1-dimensional array of string' cannot be converted to string. on
s = split(sOut.ReadToEnd(), System.Environment.NewLine)
0
 
LVL 21

Expert Comment

by:AmazingTech
ID: 24369575
Opps sorry you dim s as string.

How about this?
Function GetOSVersionThruPSINFO(ByVal strServerIP As String, ByVal strDomain As String) As String

        Dim myProcess As New System.Diagnostics.Process

        Dim s, serverOS As String

        Dim startlocation, endlocation As Integer

 

        Try

            ''''''' Starting DOS Prompt

            myProcess.StartInfo.FileName = "cmd.exe"

            myProcess.StartInfo.UseShellExecute = False

            myProcess.StartInfo.CreateNoWindow = True

            myProcess.StartInfo.RedirectStandardInput = True

            myProcess.StartInfo.RedirectStandardOutput = True

            myProcess.StartInfo.RedirectStandardError = True

 

            myProcess.Start()

 

            Dim sIn As StreamWriter = myProcess.StandardInput

            Dim sOut As StreamReader = myProcess.StandardOutput

            Dim sErr As StreamReader = myProcess.StandardError

 

            sIn.AutoFlush = True

 

            log.Info("*******************Now performing PSINFO for Incoming Server Name: " & strDomain & " - " & strServerIP)

            ''''''' This command filters everything else out....except for what I need which is the Kernal version

            sIn.Write("for /f ""tokens=2,* delims=: "" %a in ('psinfo ""kernel version"" \\" & strDomain & " ^| find /i ""kernel version""') do echo %b" & System.Environment.NewLine)

            sIn.Write("exit" & System.Environment.NewLine)

 

            '''''''' going into read mode - read the results of DOS command

            stemp = split(sOut.ReadToEnd(), System.Environment.NewLine)

 

            If Not myProcess.HasExited Then

                myProcess.Kill()

            End If

 

            sIn.Close()

            sOut.Close()

            sErr.Close()

            myProcess.Close()

            log.Info("Output of Kernel Version: " & stemp(6))

 

            serverOS = "Not Available"

            if stemp(6) <> "" then serverOS = stemp(6)

 

            Return serverOS

        Catch ex As Exception

            log.Error("Error occurred: " & ex.Message)

        End Try

    End Function

Open in new window

0
 

Author Comment

by:msyed1
ID: 24371139
It's working! but there is a but...  I used the code you sent but just changed 's' to a string array and it worked.  See code attached.  
I have close to 93 servers in an arraylist that I am processing.  See the .csv file.  For some reason after the first few, column 4 which is where I am placing the Server OS version says "'Not Available" even for servers that I know for sure are Windows servers and I can successfully do a psinfo on them through the command line.  Do you think we need to put a delay mechanism in there ?? because the psinfo command takes a long time.  I don't understand why it didn't go through and get the OS version of all those servers.  

Thank you very much.  You have helped me a lot.  msyed1.

Function GetOSVersionThruPSINFO(ByVal strServerIP As String, ByVal strDomain As String) As String

        Dim myProcess As New System.Diagnostics.Process

        Dim serverOS As String

        Dim s() As String

        Dim startlocation, endlocation As Integer
 

        Try

            ''''''' Starting DOS Prompt

            myProcess.StartInfo.FileName = "cmd.exe"

            myProcess.StartInfo.UseShellExecute = False

            myProcess.StartInfo.CreateNoWindow = True

            myProcess.StartInfo.RedirectStandardInput = True

            myProcess.StartInfo.RedirectStandardOutput = True

            myProcess.StartInfo.RedirectStandardError = True
 

            myProcess.Start()
 

            Dim sIn As StreamWriter = myProcess.StandardInput

            Dim sOut As StreamReader = myProcess.StandardOutput

            Dim sErr As StreamReader = myProcess.StandardError
 

            sIn.AutoFlush = True
 

            log.Info("*******************Now performing PSINFO for Incoming Server Name: " & strDomain & " - " & strServerIP)

            ''''''' This command filters everything else out....except for what I need which is the Kernal version

            sIn.Write("for /f ""tokens=2,* delims=: "" %a in ('psinfo ""kernel version"" \\" & strDomain & " ^| find /i ""kernel version""') do echo %b" & System.Environment.NewLine)

            sIn.Write("exit" & System.Environment.NewLine)
 

            '''''''' going into read mode - read the results of DOS command and split each line using 

            '''''''' System.Environment.Newline as the delimeter.
 

            s = split(sOut.ReadToEnd(), System.Environment.NewLine)
 

            If Not myProcess.HasExited Then

                myProcess.Kill()

            End If
 

            sIn.Close()

            sOut.Close()

            sErr.Close()

            myProcess.Close()

            log.Info("Output of Kernel Version: " & s(6))
 

            serverOS = "Not Available"

            If s(6) <> "" Then serverOS = s(6)
 

            Return serverOS

        Catch ex As Exception

            log.Error("Error occurred: " & ex.Message)

        End Try

    End Function

Open in new window

0
 

Author Comment

by:msyed1
ID: 24371154
Here is the csv file.  CSV file is not going through.  I changed it to .txt.
RuntimeInfo5122009-6-39-PM.txt
0
 
LVL 21

Accepted Solution

by:
AmazingTech earned 500 total points
ID: 24371834
Hmm.. Reading on the internet it seems that you're running this asynchronously. Basically it doesn't wait for PSINFO to finish.

Try this.

myProcess.WaitForExit()

http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx
Function GetOSVersionThruPSINFO(ByVal strServerIP As String, ByVal strDomain As String) As String

        Dim myProcess As New System.Diagnostics.Process

        Dim serverOS As String

        Dim s() As String

        Dim startlocation, endlocation As Integer

 

        Try

            ''''''' Starting DOS Prompt

            myProcess.StartInfo.FileName = "cmd.exe"

            myProcess.StartInfo.UseShellExecute = False

            myProcess.StartInfo.CreateNoWindow = True

            myProcess.StartInfo.RedirectStandardInput = True

            myProcess.StartInfo.RedirectStandardOutput = True

            myProcess.StartInfo.RedirectStandardError = True

 

            myProcess.Start()

 

            Dim sIn As StreamWriter = myProcess.StandardInput

            Dim sOut As StreamReader = myProcess.StandardOutput

            Dim sErr As StreamReader = myProcess.StandardError

 

            sIn.AutoFlush = True

 

            log.Info("*******************Now performing PSINFO for Incoming Server Name: " & strDomain & " - " & strServerIP)

            ''''''' This command filters everything else out....except for what I need which is the Kernal version

            sIn.Write("for /f ""tokens=2,* delims=: "" %a in ('psinfo ""kernel version"" \\" & strDomain & " ^| find /i ""kernel version""') do echo %b" & System.Environment.NewLine)

            sIn.Write("exit" & System.Environment.NewLine)

 

            '''''''' going into read mode - read the results of DOS command and split each line using 

            '''''''' System.Environment.Newline as the delimeter.

 

            s = split(sOut.ReadToEnd(), System.Environment.NewLine)

            myProcess.WaitForExit()
 

            If Not myProcess.HasExited Then

                myProcess.Kill()

            End If

 

            sIn.Close()

            sOut.Close()

            sErr.Close()

            myProcess.Close()

            log.Info("Output of Kernel Version: " & s(6))

 

            serverOS = "Not Available"

            If s(6) <> "" Then serverOS = s(6)

 

            Return serverOS

        Catch ex As Exception

            log.Error("Error occurred: " & ex.Message)

        End Try

    End Function

Open in new window

0
 

Author Closing Comment

by:msyed1
ID: 31580567
THANKS A LOT for working with me on this.  You've been great.  The Wait is doing the job.  msyed1.
0
 
LVL 21

Expert Comment

by:AmazingTech
ID: 24375589
OK. Great. Thanks for the grade.
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
squareUp  challenge 22 107
URL to download Windows 10 Home 2 97
Copy Files - Python 7 57
question about windows batch/script 3 40
The password reset disk is often mentioned as the best solution to deal with the lost Windows password problem. In Windows 2008, 7, Vista and XP, a password reset disk can be easily created. But besides Windows 7/Vista/XP, Windows Server 2008 and ot…
There is an easy way, in .NET, to centralize the treatment of all unexpected errors. First of all, instead of launching the application directly in a Form, you need first to write a Sub called Main, in a module. Then, set the Startup Object to th…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
Windows 8 came with a dramatically different user interface known as Metro. Notably missing from that interface was a Start button and Start Menu. Microsoft responded to negative user feedback of the Metro interface, bringing back the Start button a…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now