Easy SFTP (Secure FTP) With C# and PSFTP

There are a number of .Net projects out there that allow you to use SFTP, but all of them I’ve tried are confusing or just don’t work.  The makers of PuTTY (an open source telnet/SSH/etc client) made a command line app (PSFTP download it here) specifically for people scripting SFTP.  Essentially it’s a command line app that takes a few arguements and can run a batch script.  The code below is a basic introduction to using it with your C# apps.  It generates the batch script automatically and runs PSFTP as a Process.  For more uses of PSFTP, read the documetation here.

Two catches:

1)  You have to accept the SSH certificate from the server you’re trying to connect to prior to running the script below or it WILL NOT work, to do this, just use PuTTY or other SSH clients to connect to the server and accept its’ certificate;

2)  This is ONLY for SFTP.  For regular FTP check out my other post here.

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.IO;

using System.Linq;

using System.Text;

namespace SFTP

{

class Program

{

static void Main(string[] args)

{

string[] remoteFiles = new string[]

{

@”/etc/remote-file1.txt”,

@”/etc/remote-file2.txt”,

@”/etc/remote-file3.txt”

};

string[] localFiles = new string[]

{

@”C:\local-file1.txt”,

@”C:\local-file2.txt”,

@”C:\local-file3.txt”

};

string[] commands = new string[]

{

@”cd /home”,

@”dir”

};

PSFTP PsftpClient = new PSFTP(@”10.10.10.10″, @”root”, @”password”);

PsftpClient.Get(remoteFiles, localFiles);

PsftpClient.Put(remoteFiles, localFiles);

PsftpClient.SendCommands(commands);

Console.WriteLine(PsftpClient.Outputs);

PsftpClient = null;

}

}

class PSFTP

{

private string _Host;

private string _User;

private string _Password;

private string _BatchFilePath = @”C:\batch.txt”;

private string _PsftpPath = @”C:\psftp”; // Change this to the location of the PSTFP app.  Do not include the ‘.exe’ file extension.

public string Outputs = “”; // Stores the outputs and errors of PSFTP

/* Object Constructor for standard usage */

public PSFTP(string Host, string User, string Password)

{

_Host = Host;

_User = User;

_Password = Password;

}

/* Retrieve files from the server */

public void Get(string[] Remote, string[] Local)

{

/* Format the commands */

string[] Commands = new string[Remote.Count()];

for (int i = 0; i < Remote.Count(); i++)

{

Commands[i] = @”get “ + Remote[i] + @” “ + Local[i];

}

GenerateBatchFile(Commands);

Run();

return;

}

        /* Send files from your computer to the server */

public void Put(string[] Remote, string[] Local)

{

            /* Format the commands */

string[] Commands = new string[Remote.Count()];

for (int i = 0; i < Remote.Count(); i++)

{

Commands[i] = @”put “ + Remote[i] + @” “ + Local[i];

}

GenerateBatchFile(Commands);

Run();

return;

}

        /* Use this to send other SFTP commands (CD, DIR, etc.) */

public void SendCommands(string[] commands)

{

GenerateBatchFile(commands);

Run();

            return;

}

        /* Create a text file with a list of commands to be fed into PSFTP */

private void GenerateBatchFile(string[] Commands)

{

try

{

StreamWriter batchWriter = new StreamWriter(_BatchFilePath);

                /* Write each command to the batch file */

for (int i = 0; i < Commands.Count(); i++)

{

batchWriter.WriteLine(Commands[i]);

}

                /* Command to close the connection */

batchWriter.WriteLine(@”bye”);

batchWriter.Close();

}

catch (Exception ex) { Console.WriteLine(ex.ToString()); }

return;

}

        /* Run the commands, store the outputs */

private void Run()

{

            /* Execute PSFTP as a System.Diagnostics.Process using the supplied login info and generated batch file */

try

{

ProcessStartInfo PsftpStartInfo = new ProcessStartInfo(_PsftpPath, _User + @”@” + _Host + @” -pw “ + _Password + @” -batch -be -b “ + _BatchFilePath);

                /* Allows redirecting inputs/outputs of PSFTP to your app */

PsftpStartInfo.RedirectStandardInput = true;

PsftpStartInfo.RedirectStandardOutput = true;

PsftpStartInfo.RedirectStandardError = true;

PsftpStartInfo.UseShellExecute = false;

Process PsftpProcess = new Process();

PsftpProcess.StartInfo = PsftpStartInfo;

PsftpProcess.Start();

                /* Streams for capturing outputs and errors as well as taking ownership of the input */

StreamReader PsftpOutput = PsftpProcess.StandardOutput;

StreamReader PsftpError = PsftpProcess.StandardError;

StreamWriter PsftpInput = PsftpProcess.StandardInput;

while (!PsftpOutput.EndOfStream)

{

try

{

                        /* This is usefule for commands other than ‘put’ or ‘get’ and for catching errors. */

Outputs += PsftpOutput.ReadLine();

Outputs += PsftpError.ReadLine();

}

catch (Exception ex) { Console.WriteLine(ex.ToString()); }

}

PsftpOutput.Close();

PsftpError.Close();

PsftpInput.Close();

PsftpProcess.WaitForExit();

PsftpStartInfo = null;

PsftpProcess = null;

}

catch (Exception ex) { Console.WriteLine(ex.ToString()); }

            /* Delete the batch file */

try

{

File.Delete(_BatchFilePath);

}

catch (Exception ex) { Console.WriteLine(ex.ToString()); }

return;

}

}

}

Posted in Automation, C#, External Application, FTP, Process, PSFTP, PuTTY, SFTP

C# Web File Download with BITSadmin

I was making an app that required downloading files from a website.  In the past, I’ve used WebClient (excellent for most scenarios), HttpWebRequest (clunky), and even the Forms WebBrowser (very messy) to accomplish the deed.  For this particular app however, all of these methods failed due to the dreaded “server protocol violation” error.  Argh!!!  With some digging, I found a console executable that was right for the job, so I made a simple method to use it in my app.  Success!

//
//

Using the method

string local = @”C:\Users\metastruct\Desktop\my_image.jpg”;

string remote = @”http://www.test.com/some_image.jpg&#8221;;

download(remote, local);

That easy to use!  Below is the code snippet:

private void download(string remote_file_url, string local_file)
{

try
{

/* Create the Process */
System.Diagnostics.Process bitsadmin_process = new System.Diagnostics.Process();
/* Assign the BITSadmin Executable and Arguements to the Process */
bitsadmin_process.StartInfo = new System.Diagnostics.ProcessStartInfo(“bitsadmin”, “/transfer mydownloadjob  /download /priority normal “ + remote_file_url + ” “ + local_file);
/* Start the Process */
bitsadmin_process.Start();
/* Wait While the File Downloads */
bitsadmin_process.WaitForExit();
/* Dispose the Process */
bitsadmin_process = null;

}
catch { }

return;

}

Such a simple solution to such an annoying problem.  Next step would be some improved error handling/redirection from the Process, but this works for now.

Tagged with: , , , , , ,
Posted in Uncategorized

Easy C# FTP Class

I created this class for use in a variety of applications as a simplified FTP client.  It’s versatile and simple to use.  Here are examples of using the class:

/* Create Object Instance */
ftp myFtpClient = new ftp(@”ftp://10.10.10.10/”, “user”, “password”);

/* Upload a File */
myFtpClient.upload(“etc/test.txt”, @”C:\Users\metastruct\Desktop\test.txt”);

/* Download a File */
myFtpClient.download(“etc/test.txt”, @”C:\Users\metastruct\Desktop\test.txt”);

/* Delete a File */
myFtpClient.delete(“etc/test.txt”);

/* Rename a File */
myFtpClient.rename(“etc/test.txt”, “test2.txt”);

/* Create a New Directory */
myFtpClient.createDirectory(“etc/test”);

/* Get the Date/Time a File was Created */
string fileDateTime = myFtpClient.getFileCreatedDateTime(“etc/test.txt”);
Console.WriteLine(fileDateTime);

/* Get the Size of a File */
string fileSize = myFtpClient.getFileSize(“etc/test.txt”);
Console.WriteLine(fileSize);

/* Get Contents of a Directory (Names Only) */
string[] simpleDirectoryListing = myFtpClient.directoryListDetailed(“/etc”);
for (int i = 0; i < simpleDirectoryListing.Count(); i++) { Console.WriteLine(simpleDirectoryListing[i]); }

/* Get Contents of a Directory with Detailed File/Directory Info */
string[] detailDirectoryListing = myFtpClient.directoryListDetailed(“/etc”);
for (int i = 0; i < detailDirectoryListing.Count(); i++) { Console.WriteLine(detailDirectoryListing[i]); }

myFtpClient = null;

Here is the code:

class ftp
{

private string host = null;
private string user = null;
private string pass = null;
private FtpWebRequest ftpRequest = null;
private FtpWebResponse ftpResponse = null;
private Stream ftpStream = null;
private int bufferSize = 2048;

/* Construct Object */
public ftp(string hostIP, string userName, string password) { host = hostIP; user = userName; pass = password; }

/* Download File */
public void download(string remoteFile, string localFile)
{

try
{
/* Create an FTP Request */
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + “/” + remoteFile);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* When in doubt, use these options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
/* Establish Return Communication with the FTP Server */
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
/* Get the FTP Server’s Response Stream */
ftpStream = ftpResponse.GetResponseStream();
/* Open a File Stream to Write the Downloaded File */
FileStream localFileStream = new FileStream(localFile, FileMode.Create);
/* Buffer for the Downloaded Data */
byte[] byteBuffer = new byte[bufferSize];
int bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);

/* Download the File by Writing the Buffered Data Until the Transfer is Complete */
try
{

while (bytesRead > 0)
{

localFileStream.Write(byteBuffer, 0, bytesRead);
bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);

}

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }

/* Resource Cleanup */
localFileStream.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
return;

}

/* Upload File */
public void upload(string remoteFile, string localFile)
{

try
{

/* Create an FTP Request */
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + “/” + remoteFile);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* When in doubt, use these options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
/* Establish Return Communication with the FTP Server */
ftpStream = ftpRequest.GetRequestStream();
/* Open a File Stream to Read the File for Upload */
FileStream localFileStream = new FileStream(localFile, FileMode.Create);
/* Buffer for the Downloaded Data */
byte[] byteBuffer = new byte[bufferSize];
int bytesSent = localFileStream.Read(byteBuffer, 0, bufferSize);
/* Upload the File by Sending the Buffered Data Until the Transfer is Complete */
try
{

while (bytesSent != 0)
{

ftpStream.Write(byteBuffer, 0, bytesSent);
bytesSent = localFileStream.Read(byteBuffer, 0, bufferSize);

}

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
/* Resource Cleanup */
localFileStream.Close();
ftpStream.Close();
ftpRequest = null;

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
return;

}

/* Delete File */
public void delete(string deleteFile)
{

try
{

/* Create an FTP Request */
ftpRequest = (FtpWebRequest)WebRequest.Create(host + “/” + deleteFile);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* When in doubt, use these options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.DeleteFile;
/* Establish Return Communication with the FTP Server */
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
/* Resource Cleanup */
ftpResponse.Close();
ftpRequest = null;

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
return;

}

/* Rename File */
public void rename(string currentFileNameAndPath, string newFileName)
{

try
{

/* Create an FTP Request */
ftpRequest = (FtpWebRequest)WebRequest.Create(host + “/” + currentFileNameAndPath);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* When in doubt, use these options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.Rename;
/* Rename the File */
ftpRequest.RenameTo = newFileName;
/* Establish Return Communication with the FTP Server */
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
/* Resource Cleanup */
ftpResponse.Close();
ftpRequest = null;

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
return;

}

/* Create a New Directory on the FTP Server */
public void createDirectory(string newDirectory)
{

try
{

/* Create an FTP Request */
ftpRequest = (FtpWebRequest)WebRequest.Create(host + “/” + newDirectory);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* When in doubt, use these options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.MakeDirectory;
/* Establish Return Communication with the FTP Server */
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
/* Resource Cleanup */
ftpResponse.Close();
ftpRequest = null;

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
return;

}

/* Get the Date/Time a File was Created */
public string getFileCreatedDateTime(string fileName)
{

try
{

/* Create an FTP Request */
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + “/” + fileName);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* When in doubt, use these options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.GetDateTimestamp;
/* Establish Return Communication with the FTP Server */
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
/* Establish Return Communication with the FTP Server */
ftpStream = ftpResponse.GetResponseStream();
/* Get the FTP Server’s Response Stream */
StreamReader ftpReader = new StreamReader(ftpStream);
/* Store the Raw Response */
string fileInfo = null;
/* Read the Full Response Stream */
try { fileInfo = ftpReader.ReadToEnd(); }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
/* Resource Cleanup */
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
/* Return File Created Date Time */
return fileInfo;

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
/* Return an Empty string Array if an Exception Occurs */
return “”;

}

/* Get the Size of a File */
public string getFileSize(string fileName)
{

try
{

/* Create an FTP Request */
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + “/” + fileName);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* When in doubt, use these options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.GetFileSize;
/* Establish Return Communication with the FTP Server */
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
/* Establish Return Communication with the FTP Server */
ftpStream = ftpResponse.GetResponseStream();
/* Get the FTP Server’s Response Stream */
StreamReader ftpReader = new StreamReader(ftpStream);
/* Store the Raw Response */
string fileInfo = null;
/* Read the Full Response Stream */
try { while (ftpReader.Peek() != -1) { fileInfo = ftpReader.ReadToEnd(); } }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
/* Resource Cleanup */
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
/* Return File Size */
return fileInfo;

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
/* Return an Empty string Array if an Exception Occurs */
return “”;

}

/* List Directory Contents File/Folder Name Only */
public string[] directoryListSimple(string directory)
{

try
{

/* Create an FTP Request */
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + “/” + directory);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* When in doubt, use these options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
/* Establish Return Communication with the FTP Server */
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
/* Establish Return Communication with the FTP Server */
ftpStream = ftpResponse.GetResponseStream();
/* Get the FTP Server’s Response Stream */
StreamReader ftpReader = new StreamReader(ftpStream);
/* Store the Raw Response */
string directoryRaw = null;
/* Read Each Line of the Response and Append a Pipe to Each Line for Easy Parsing */
try { while (ftpReader.Peek() != -1) { directoryRaw += ftpReader.ReadLine() + “|”; } }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
/* Resource Cleanup */
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
/* Return the Directory Listing as a string Array by Parsing ‘directoryRaw’ with the Delimiter               you Append (I use | in This Example) */
try { string[] directoryList = directoryRaw.Split(“|”.ToCharArray()); return directoryList; }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
/* Return an Empty string Array if an Exception Occurs */
return new string[] { “” };

}

/* List Directory Contents in Detail (Name, Size, Created, etc.) */
public string[] directoryListDetailed(string directory)
{

try
{

/* Create an FTP Request */
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + “/” + directory);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* When in doubt, use these options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
/* Establish Return Communication with the FTP Server */
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
/* Establish Return Communication with the FTP Server */
ftpStream = ftpResponse.GetResponseStream();
/* Get the FTP Server’s Response Stream */
StreamReader ftpReader = new StreamReader(ftpStream);
/* Store the Raw Response */
string directoryRaw = null;
/* Read Each Line of the Response and Append a Pipe to Each Line for Easy Parsing */
try { while (ftpReader.Peek() != -1) { directoryRaw += ftpReader.ReadLine() + “|”; } }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
/* Resource Cleanup */
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
/* Return the Directory Listing as a string Array by Parsing ‘directoryRaw’ with the Delimiter               you Append (I use | in This Example) */
try { string[] directoryList = directoryRaw.Split(“|”.ToCharArray()); return directoryList; }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }

}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
/* Return an Empty string Array if an Exception Occurs */
return new string[] { “” };

}

}

Be sure to leave a comment if this helps or if you have any suggestions!

Tagged with: , , , ,
Posted in C#, FTP

Multithreaded, Customizable SysLog Server – C#

For those of us managing multiple devices, keeping aware of issues and events can be a challenge.  Many Linux, Unix, and Windows devices support the ability to send SysLog (System Log) events to a central server for notifications and/or logging.  I decided to make this application using C# (Visual Studio Express 2010) to receive those messages, store them in CSV format and send me email notifications based on custom criteria I define.  I chose CSV because it’s light weight and can natively be opened by any spreadsheet software or brought in to another app as a DataTable with a simple OleDb connection.  For my purposes, multithreading this app was essential due to the volume of devices configured to send SysLogs to the server.  I let this app run for a bit and looked through the output CSV file to determine which events I should be made aware of via email, and set those as email triggers.  This is a relatively light weight console app that is very versatile for a number of uses.  Check out the code and leave a comment with any questions or suggestions!

Configure your “devices” to aim their SysLog events to the IP of your computer (you’ll probably want a static or reserved IP for this to work well).  Create a Console application is Visual Studio, and use the following code:

using System;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace syslog
{
class Program
{
static void Main(string[] args)
{
IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
UdpClient udpListener = new UdpClient(514);
byte[] bReceive; string sReceive; string sourceIP;

/* Main Loop */
/* Listen for incoming data on udp port 514 (default for SysLog events) */
while (true)
{
try
{
bReceive = udpListener.Receive(ref anyIP);
sReceive = Encoding.ASCII.GetString(bReceive); /* Convert incoming data from bytes to ASCII */
sourceIP = anyIP.Address.ToString(); /* Get the IP of the device sending the syslog */
new Thread(new logHandler(sourceIP, sReceive).handleLog).Start(); /* Start a new thread to handle received syslog event */
}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
}
}
}

class logHandler
{
private string[] emailTriggers = new string[] { “link loss”, “help please” }; /* Phrases within the syslog that will trigger an email notification */
private string outputPath = @”C:\Users\metastruct\Desktop\syslog.csv”; /* Location to store events */
private string source; private string log;

public logHandler(string sourceIP, string logData) /* Initialize object and clean up the raw data */
{
source = sourceIP.Trim(); /* Client IP */
log = logData.Replace(Environment.NewLine, “”).Trim(); /* Syslog data */
}

public void handleLog() /* Store the syslog and determine whether to trigger an email notification */
{
new Thread(new outputCsvRow(outputPath, new string[] { source, log }).addRow).Start(); /*                Store the syslog using a new thread */
for (int i = 0; i < emailTriggers.Count(); i++) { if (log.Contains(emailTriggers[i])) { emailEvent(); } } /* Search for trigger strings and send email if found */
return;
}

private void emailEvent() /* Send email notification */
{
try
{
MailMessage notificationEmail = new MailMessage();
notificationEmail.Subject = “SysLog Event”;
notificationEmail.IsBodyHtml = true;
notificationEmail.Body = “<b>SysLog Event Triggered:<br/><br/>Time: </b><br/>” + DateTime.Now.ToString() + “<br/><b>Source IP: </b><br/>” + source + “<br/><b>Event: </b><br/>” + log; /* Throw in some basic HTML for readability */
notificationEmail.From = new MailAddress(“SysLog@metastruct.com”, “SysLog Server”); /* From Address */
notificationEmail.To.Add(new MailAddress(“metastructblog@gmail.com”, “metastruct”)); /* To Address */
SmtpClient emailClient = new SmtpClient(“10.10.10.10″); /* Address of your SMTP server of choice */
//emailClient.UseDefaultCredentials = false; /* If your SMTP server requires credentials to send email */
//emailClient.Credentials = new NetworkCredential(“username”, “password”); /* Supply User Name and Password */
emailClient.DeliveryMethod = SmtpDeliveryMethod.Network;
emailClient.Send(notificationEmail); /* Send the email */
}
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
return;
}
}

class outputCsvRow
{
private string formattedRow = null;
private string outputPath = null;

public outputCsvRow(string filePath, string[] columns) /* Initialize object */
{
outputPath = filePath;
formattedRow = (char)34 + DateTime.Now.ToString() + (char)34; /* Construct csv row starting with the timestamp */
for (int i = 0; i < columns.Count(); i++) { formattedRow += “,” + (char)34 + columns[i] + (char)34; }
}

public void addRow()
{
int attempts = 0;
bool canAccess = false;
StreamWriter logWriter = null;
if (!File.Exists(outputPath)) /* If the file doesn’t exist, give it some column headers */
{
logWriter = new StreamWriter(outputPath, true);
logWriter.WriteLine((char)34 + “Event_Time” + (char)34 + “,” + (char)34 + “Device_IP” + (char)34 + “,” + (char)34 + “SysLog” + (char)34);
logWriter.Close();
}
/* Thread safety first! This is a poor man’s SpinLock */
while (true)
{
try
{
logWriter = new StreamWriter(outputPath, true); /* Try to open the file for writing */
canAccess = true; /* Success! */
break;
}
catch (IOException ex)
{
if (attempts < 15) { attempts++; Thread.Sleep(50); }
else { Console.WriteLine(ex.ToString()); break; } /* Give up after 15 attempts */
}
}
if (canAccess) /* Write the line if the file is accessible */
{
logWriter.WriteLine(formattedRow);
logWriter.Close();
}
return;
}
}
}

 

An additional feature that may prove useful would be a function to cross reference IP addresses with a more “user friendly” device name.  This would be most useful if the emails or logs are being used by multiple users, or if there are a large amount of devices and remembering the IP addresses of all of them isn’t probable.  For my “live” application, I also use that feature and separate log files for each device.  Word of warning, some devices send TONS of these events and your light weight CSV file can become enormous if you let it.  I also added some code in the Main block to archive the logs on a rolling 7 day basis.  For that you’ll probably have to halt receiving logs briefly to avoid an IOException.

Tagged with: , , , , , , ,
Posted in C#, Multithreading, SysLog, UdpClient
Follow

Get every new post delivered to your Inbox.