OWASP O2 Platform Blog

API_ConsoleOut.cs – New and InProcess Capture of the Console Output

There are multiple scenarious where it is usefull to capture (via Lambda callbacks) the calls to Console.Write. Most solutions out there are based on using the Process class (via its ProcessStartInfo settings):

The problem with those solutions is they are able to capture the Console Output of the new process created, NOT the current process (which is what I want since I need to see the Console messages created by an external API/Code that I consuming from O2)

Using O2 to captute Console Output of new processes

Note: If all you want to do is to capture the console output of a new process, there are a bunch of O2 methods/APIs that can help you with it:

Which can be used like this:

run cmd.exe (with params: /c dir) and get its console output

return "cmd.exe".startProcess_getConsoleOut(" /c dir");

run netstat.exe (with params: -na) and redirect its console into a lambda method

"netstat.exe".startProcess("-na", (line)=> line.info());

run netstat.exe and show its results in a table list

var topPanel = panel.clear().add_Panel();
var tableList = topPanel.add_TableList();
var lines = "netstat.exe".startProcess_getConsoleOut("-na")
                         .lines()
                         .removeRange(0,2);
var netstatData = (from line in lines
                   let fragments = line.split(" ").removeEmpty()
                   select new {
                                   @Type = fragments.value(0) , 
                                   Local_Address = fragments.value(1) ,
                                   Foreign_Address = fragments.value(2) ,
                                   State = fragments.value(3)
                                  });                  
tableList.show(netstatData);

Using O2 to captute Console Output in the current Process

To capture the Console Output in the current process, I first tried to capture the usage of a MemoryStream in a way simular to how Console actually works (see O2 blog post Dynamically creating private/internal types and delegates (UserCallBack and AsyncStreamReader) ) , but a much easier way is to specify a TextWriter via Console.SetOut.

To make it easier to use, I created the API_ConsoleOut class which can be used like this:

Show Console Ouput in a new window

"Write this to the console :)".open_ConsoleOut();
Console.Write("another");
Console.WriteLine("test");
//O2File:API_ConsoleOut.cs

Which looks like this:

 Show Console Output in an existing panel/control

var topPanel = panel.clear().add_Panel();
topPanel.show_ConsoleOut(); //this will open as a child of an existing control
Console.Write("another ");
Console.WriteLine("test");
topPanel.insert_Right().add_SourceCodeViewer().set_Text("<h1>some html<h1>",".html");
Console.WriteLine("now inside a Windows Control");

return "done";
//O2File:API_ConsoleOut.cs

Which looks like this:

 

Test GUI with Console Input

If you want to test the Console Input and Output, there is also a test GUI that you can use

var apiConsoleOut = new API_ConsoleOut();
apiConsoleOut.show_ConsoleOut_TestGui();

Console.Write("another ");
Console.WriteLine("test");
Console.WriteLine("now with more options");

//O2File:API_ConsoleOut.cs

Which looks like this:

Source code of API_Console_Out.cs

using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
using O2.Interfaces.O2Core;
using O2.Kernel;
using O2.Kernel.ExtensionMethods;
using O2.DotNetWrappers.ExtensionMethods;
using O2.Views.ASCX.classes.MainGUI;
using O2.XRules.Database.Utils;

//O2File:_Extra_methods_Misc.cs
//O2File:_Extra_methods_Windows.cs
//O2File:_Extra_methods_WinForms_Controls.cs

namespace O2.XRules.Database.APIs
{
    public class API_ConsoleOut : Control
    {            
        public O2StreamWriter o2StreamWriter;
       
        public API_ConsoleOut()
        {       
            this.o2StreamWriter = new O2StreamWriter();     
            this.o2StreamWriter.Name = "API_ConsoleOut";
            Console.SetOut(this.o2StreamWriter); 
        }
    }
   
    public class O2StreamWriter : TextWriter
    {
        public StringBuilder ConsoleOut     { get; set; }
        public StringBuilder CurrentLine    { get; set; }
        public List<string> Lines            { get; set; }
        public Action<char> On_NewChar        { get; set; }   
        public Action<string> On_NewLine     { get; set; }
        public bool LogAllChars                { get; set; }
        public bool LogAllLines                { get; set; }
        public string Name                    { get; set; }
        public int PauseBetweenCharWrite    { get; set; }
       
        public O2StreamWriter()
        {
            ConsoleOut = new StringBuilder();
            CurrentLine = new StringBuilder();
            Lines = new List<string>();       
            LogAllChars = false;
            LogAllLines = true;
            Name = "O2StreamWriter";
        }
   
        public override void Write(char value)
        {
            base.Write(value);
              this.ConsoleOut.Append(value.ToString());             
             
              if (value == '\n')
                  handleLine();                 
              else
                  this.CurrentLine.Append(value.ToString());
                 
              if (this.LogAllChars)
                "[{0}] char: {1}".info(this.Name, value);
           
            if (this.On_NewChar.notNull())
                this.On_NewChar(value);
           
            if (PauseBetweenCharWrite > 0)
                this.sleep(PauseBetweenCharWrite, false);
        }               
       
        public void handleLine()
        {
            var line = this.CurrentLine.str();
            if (line.lastChar('\r'))
                line = line.removeLastChar();
            this.CurrentLine = new StringBuilder();
            this.Lines.add(line);
           
            if (this.LogAllLines)
                "[{0}]: {1}".info(this.Name, line);
               
            if (this.On_NewLine.notNull())
                this.On_NewLine(line);           
        }
        public override Encoding Encoding
        {
            get { return System.Text.Encoding.UTF8; }
        }
    }
   
    public static class API_ConsoleOut_ExtensionMethods_TestGuis
    {
       
        public static API_ConsoleOut show_ConsoleOut_TestGui(this API_ConsoleOut apiConsoleOut)
        {
            var topPanel = O2Gui.open<Panel>("Console.Out capture Test",700,200);
            return apiConsoleOut.show_ConsoleOut_TestGui(topPanel);
        }
       
       
        public static API_ConsoleOut show_ConsoleOut_TestGui(this API_ConsoleOut apiConsoleOut, Control topPanel)
        {
            var consoleIn = topPanel.insert_Above(40, "ConsoleIn");
            var lines_TextBox = topPanel.clear().add_GroupBox("Console.Out Lines").add_TreeView();
            var chars_TextBox = topPanel.insert_Right("Console.Out Chars").add_TextArea();
                       
            consoleIn.add_TextBox("Write to send to Console Input ->","")
                     .onKeyPress_getChar( (_char)=> { if (_char == '\x0d') Console.WriteLine(); else  Console.Write(_char); })
                     .multiLine(true)
                     .focus();
                                
            apiConsoleOut.o2StreamWriter.On_NewChar = (_char) => chars_TextBox.append_Text(_char.str());
            apiConsoleOut.o2StreamWriter.On_NewLine = (line) => lines_TextBox.add_Node(line);
           
            //apiConsoleOut.o2StreamWriter.PauseBetweenCharWrite = 1;            
           
            Console.WriteLine("Welcome to show_ConsoleOut_TestGui");   
            Console.Write("Type something on the TextBox above to see it here".line());
            return apiConsoleOut;
        }
       
        public static API_ConsoleOut open_ConsoleOut(this string message)
        {
            return message.show_ConsoleOut();
        }
       
        public static API_ConsoleOut show_ConsoleOut(this string message)
        {
            var apiConsoleOut = new API_ConsoleOut();
            apiConsoleOut.show_ConsoleOut();
            Console.WriteLine(message);
            return apiConsoleOut;
        }
       
        public static API_ConsoleOut add_ConsoleOut(this Control topPanel)
        {
            return topPanel.show_ConsoleOut();
        }
       
        public static API_ConsoleOut show_ConsoleOut<T>(this T topPanel)
            where T : Control
        {
            return topPanel.show_ConsoleOut("Welcome to O2's console");
        }
       
        public static API_ConsoleOut show_ConsoleOut<T>(this T topPanel, string message )
            where T : Control
        {
            var apiConsoleOut = new API_ConsoleOut();
            apiConsoleOut.show_ConsoleOut(topPanel);
            Console.WriteLine(message);
            return apiConsoleOut;
        }
       
        public static API_ConsoleOut show_ConsoleOut(this API_ConsoleOut apiConsoleOut)
        {
            var topPanel = O2Gui.open<Panel>("Console.Out",700,200);
            return apiConsoleOut.show_ConsoleOut(topPanel);
        }
       
       
        public static API_ConsoleOut show_ConsoleOut(this API_ConsoleOut apiConsoleOut, Control topPanel)
        {
            var consoleOut = topPanel.add_TextArea();
            consoleOut.backColor(Color.Black);
            consoleOut.foreColor(Color.White);
            consoleOut.font("Lucida Console");
            apiConsoleOut.o2StreamWriter.On_NewChar = (_char) => consoleOut.append_Text(_char.str());
            apiConsoleOut.o2StreamWriter.LogAllLines = false;
           
            consoleOut.add_ContextMenu()
                      .add_MenuItem("Clear", false, ()=> consoleOut.set_Text(""))
                      .add_MenuItem("Write to Console Input", ()=> Console.WriteLine("Text to send to Console.Input".askUser()));
            return apiConsoleOut;
        }
    }
}

November 26, 2011 Posted by | .NET, Tools | 3 Comments

O2 Script: Util – Util – Show Open Ports (via NetStat -afo).h2

Here is are two scripts that show how to parse ‘kind-off’ unstructured data into a table.

In the first example we grab the output from netstat -fa , parse it in order to extract the port numbers and display it on a table. The 2nd example uses netstat-fao which will also contain the process id (which is used by the script to find the process name)

For reference,  in netstat

  • a = Displays all connections and listening ports
  • f = Displays Fully Qualified Domain Names (FQDN) for foreign addresses.
  • o = Displays the owning process ID associated with each connection

1st version (netstat -fa)

var topPanel = O2Gui.open<Panel>("Util - Show Open Ports (via NetStat -na)",700,600);
//var topPanel = panel.clear().add_Panel();
var tableList = topPanel.add_TableList();

Action showNetStatOnTable =
    ()=>{
            var lines = "netstat.exe".startProcess_getConsoleOut("-na")
                                     .lines()
                                     .removeRange(0,2);
            var netstatData = (from line in lines
                               let fragments = line.split(" ").removeEmpty()
                               let value0 = fragments.value(0)
                               let value1 = fragments.value(1)
                               let value2 = fragments.value(2)
                               let value3 = fragments.value(3)
                               select new {
                                               @Type = value0 ,  
                                               //Local_Address = value1,
                                               Local_Address_IP = value1.replace("::","__").split(":")[0].replace("__","::"),
                                               Local_Address_Port =  value1.replace("::","__").split(":")[1] ,
                                               //Foreign_Address = value2 ,
                                               Foreign_Address_IP = value2.replace("::","__").split(":")[0].replace("__","::"),
                                               Foreign_Address_Port =  value2.replace("::","__").split(":")[1] ,
                                               State = value3
                                              });       
            tableList.show(netstatData);                                 
        }; 

topPanel.insert_Above(40, "Actions")
        .add_Link("Refresh", ()=> showNetStatOnTable())
        .click();

2nd version (netstat -fao)

var topPanel = O2Gui.open<Panel>("Util - Show Open Ports (via NetStat -afo)",700,600);
//var topPanel = panel.clear().add_Panel();

var tableList = topPanel.add_TableList();
tableList.title("Table showing parsed version of netstat command");
var selectedProcess = 0;

Action showNetStatOnTable =
    ()=>{
            var lines = "netstat.exe".startProcess_getConsoleOut("-afo")
                                     .lines()
                                     .removeRange(0,2);
            var netstatData = (from line in lines
                               let fragments = line.split(" ").removeEmpty()
                               let value0 = fragments.value(0)
                               let value1 = fragments.value(1)
                               let value2 = fragments.value(2)
                               let value3 = fragments.value(3)
                               let value4 = fragments.value(4)                              
                               select new {
                                               @Type = value0 ,  
                                               //Local_Address = value1,
                                               Local_Address_IP = value1.replace("::","__").split(":")[0].replace("__","::"),
                                               Local_Address_Port =  value1.replace("::","__").split(":")[1] ,
                                               //Foreign_Address = value2 ,
                                               Foreign_Address_IP = value2.replace("::","__").split(":")[0].replace("__","::"),
                                               Foreign_Address_Port =  value2.replace("::","__").split(":")[1] ,
                                               State = value3,
                                               Process_ID = value4,
                                               Process_Name = Processes.getProcess(value4.toInt()).ProcessName //,
                                               //Executable = value5
                                              });       
            tableList.show(netstatData);                                 
        }; 
       
Action stopSelectedProcess =
    ()=>{
            if (selectedProcess ==0)
                "Cannot Stop process with ID 0".error();
            else
            {
                var process = Processes.getProcess(selectedProcess);               
                "Stopping process: {0} (id: {1})".info(process.ProcessName, process.Id);
                process.stop()
                       .WaitForExit();
                showNetStatOnTable();
            }
        };

topPanel.insert_Above(40, "Actions")
        .add_Link("Refresh", ()=> showNetStatOnTable())
        .append_Link("Stop Selected Process", ()=> stopSelectedProcess()).leftAdd(100);
       

tableList.add_ContextMenu()
         .add_MenuItem("Stop Selected Process", ()=> stopSelectedProcess());
        
tableList.afterSelect_get_Cell(6,
            (value)=> {
                        selectedProcess = value.toInt();
                        "selectedProcess: {0}".info(selectedProcess);
                      });
                     
showNetStatOnTable();
//return "netstat.exe".startProcess_getConsoleOut("-afo");       
return "ok";       

This script is now part of O2’s Scripts as Util – Show Open Ports (via NetStat -afo).h2

November 26, 2011 Posted by | Network Security, Tools | Leave a comment