My windows service needs to save the contents of one eventlog to a file. This is done by EventLogSession.ClearLog. However, i cannot force it to save the eventlog to CSV directly. The saved format is EVTX.
EventLogSession els = new EventLogSession();
//stel de filename samen door het appdata pad te combinen met een tempfile name
string tempData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "templog.csv");
// Clears all the events and archives them to the .evtx file
els.ClearLog(eventLogName, tempData); // Backup File Path
How can i force the EventlogSession class to save directly to CSV, or, if that is impossible. How do i convert an EVTX to CSV (using C# or VB.net)
Thanks!
This is pretty easy to do with the API provided by Log Parser.
Download & Install Log Parser 2.2
Add a reference to the COM library "MS Utility 1.0 Type Library - LogParser Interfaces collection". Searching for Log narrowed the list pretty dramatically.
Change the properties of the Reference so that the it does NOT embed Interop Types.
If you don't do this, you will get compile errors like this:
Interop type 'MSUtil.COMCSVOutputContextClassClass' cannot be embedded. Use the applicable interface instead.
The contents of the LogParser help file have a great reference for the API, but I've included the parts I used inline with the code.
using System;
using MSUtil;
namespace LogParserTest
{
using LogQuery = LogQueryClassClass;
using EventLogInput = COMEventLogInputContextClassClass;
using CSVOutput = COMCSVOutputContextClassClass;
using XMLOutput = COMXMLOutputContextClassClass;
class Program
{
static void Main(string[] args)
{
try
{
// Instantiate the LogQuery object
LogQuery oLogQuery = new LogQuery();
// Instantiate the Event Log Input Format object
EventLogInput eventInputFormat = new EventLogInput();
// When set to "FW", events are retrieved from the oldest to the
// newest. When set to "BW", events are retrieved from the newest
// to the oldest.
eventInputFormat.direction = "FW";
// Event text messages often span multiple lines. When this parameter
// is set to "ON", the EVT input format preserves readability of the
// messages by removing carriage-return, line-feed, and multiple space
// characters from the message text.
// When this parameter is set to "OFF", the EVT input format returns
// the original message text with no intervening post-processing.
eventInputFormat.formatMessage = true;
eventInputFormat.binaryFormat = "ASC";
eventInputFormat.stringsSep = ",";
CSVOutput csvOutputFormat = new CSVOutput();
// ON: always write the header;
// OFF: never write the header;
// AUTO: write the header only when not appending to an existing file.
csvOutputFormat.headers = "ON";
// Setting this parameter to "ON" causes the CSV output format to write
// a tab character after each comma field separator, in order to
// improve readability of the CSV output. Note that using tabs between
// field values might generate output that is not compatible with
// certain spreadsheet applications.
csvOutputFormat.tabs = false;
// ON: always enclose field values within double-quote characters;
// OFF: never enclose field values within double-quote characters;
// AUTO: enclose within double-quote characters only those field
// values that contain comma (,) characters.
csvOutputFormat.oDQuotes = "AUTO";
// This parameter specifies the date and/or time format to use when
// formatting values of the TIMESTAMP data type.
csvOutputFormat.oTsFormat = "yyyy-MM-dd";
// 0 is the system codepage, -1 is UNICODE.
csvOutputFormat.oCodepage = -1;
// 0: existing files are appended with the output;
// 1: existing files are overwritten with the output;
// 2: existing files are left intact, discarding the output.
csvOutputFormat.fileMode = 1;
/*
EventLog STRING Name of the Event Log or Event Log backup file
RecordNumber INTEGER Index of this event
TimeGenerated TIMESTAMP Event generated date/time (local time)
TimeWritten TIMESTAMP Event logged date/time (local time)
EventID INTEGER The ID of the event
EventType INTEGER The numeric type of the event
EventTypeName STRING The descriptive type of the event
EventCategory INTEGER The numeric category of the event
EventCategoryName STRING The descriptive category of the event
SourceName STRING The source that generated the event
Strings STRING The textual data
ComputerName STRING The name of the computer
SID STRING The Security Identifier associated with the event
Message STRING The full event message
Data STRING The binary data associated with the event
*/
string query = #"SELECT TOP 10 EventLog, RecordNumber, Message INTO "
// Enclose path in single ticks to handle spaces.
query += "'" + FullPathToCsv + "' FROM ";
// Name of application Log, System, Security, Application, CustomLogName
query += "System";
oLogQuery.ExecuteBatch(query, eventInputFormat, csvOutputFormat);
}
catch (System.Runtime.InteropServices.COMException ex)
{
Console.WriteLine("Unexpected error: " + ex.Message);
}
}
}
}
This Powershell function is the most efficient I could find. Not C# code, but I thought it might be useful. It takes a filename (evtx) or a variable array of file names in Powershell like this:
[array]$filelist =
"file1",
"file2",
"file3"
Function Convert-Logs3 {
[cmdletbinding()]
Param(
$filelist=$NULL
)
$filelist | foreach-object {
Get-WinEvent -Path "$PSItem"| Select RecordID,ID,TimeCreated, Message | export-csv - ``notypeinformation -path $(write "$PSItem.csv");
[System.gc]::collect();
}}
If you just want a tool that converts EVTX to CSV, you can use the LogParser tool directly:
C:\> logparser "SELECT TimeGenerated, SourceName, EventCategoryName, EventId, Message INTO C:\eventlog.csv FROM C:\eventlog.evtx" -i:EVT
I was able to use that to convert a 3 GB EVTX file to CSV in about 10 minutes.
It turned out that all existing solutions didn't meet my requirements.
I simply wanted a tool that takes an evtx as input and exportes a csv. Nothing more nothing less.
I built one myself and it workes fine. Its called EVTX2CSV
You can download it here: http://essaver.net/evtxecsv or directly via http://www.essaver.net/downloads/setupevtx2csv.exe
Related
I am using Directory.CreateDirectory(string) method to create folders, now the problem is if the user enters string as:
"C:\folder1" then it creates the folder in the respective location, fine by me.
but if he writes
"C:\\\\\\\\\\\\\\\\\\\\\\\\\folder1" it is also navigating to the same path, creates folder and not giving any error, this is a problem for me.
So in order to solve the above mentioned problem I try to do some validation before on the path and I tried with Path.GetFullPath() and other Path methods and I see:
Path.GetFullPath("C:\\\\folder1") no exception or error
Path.GetFullPath("C:\\\folder1") exception or error
somehow when the count of backslashes are in even number no exception is thrown but when the count is in odd number then exception is thrown.
How can I achieve this simple thing that when user enters path like:
C:\folder 1 valid path
C:\\\\\\folder1 invalid path
Please let me know if further details are required
Possible solution using FolderBrowserDialog - Users will not manually input the path but rather select/create it via FolderBrowserDialog.
The below code will return all the files in a folder but you can amend it to return whatever information you need.
private void Form1_Load(object sender, EventArgs e)
{
//
// This event handler was created by double-clicking the window in the designer.
// It runs on the program's startup routine.
//
DialogResult result = folderBrowserDialog1.ShowDialog();
if (result == DialogResult.OK)
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
}
}
Code found here
If you want to get a proper path from that, maybe you can use the following technique (in addition to what you already have, of course, this is only to remove the repeated backslashes)
Split the path using the '\' character
Remove the empty values (you can filter here the non valid
characters, etc)
Reconstruct the path string using join with the character '\' again
Something like:
pathString = "C:\\\\\\folder1";
splitString = pathString.Split('\\');
nonEmpty = splitString.Where(x => !string.IsNullOrWhiteSpace(x));
reconstructed = string.Join("\\", nonEmpty.ToArray());
Test code here: https://dotnetfiddle.net/qwVqv8
What about sanitizing the path?
char[] separator = new char[] { System.IO.Path.DirectorySeparatorChar };
string inputPath = "C:\\\\\\\folder1";
string[] chunks = inputPath.Split(separator, StringSplitOptions.RemoveEmptyEntries);
string validPath = String.Join(new string(separator), chunks);
Need help formatting a seperated .txt file in C#. I have a text file that contains a directory listing and looks like as follows when I open up in notepad or ultra-edit. First column is date and time, next column is the size of file in bytes, third column is the username and fourth column is the name of the file. Each column is separated by one or more spaces, and the filename column at the end can contain spaces in the filename. They consist of more directories and the total amount of lines in the file is about 200,000.
Directory of V:\word
01/10/2013 12:30 PM 23,000 BUILTIN/ADMINISTRATOR FILE NAME.XLS
10/25/2013 10:39 AM 1,332,432 AMERICAS/DOEJ FILENAME2.CSV
11/31/2000 09:54 PM 21,999,999 AMERICAS/DOEF F_I_L_E_N_A_M_E_4.PDF
Directory of V:\word\administrators
01/10/2013 12:30 PM 23,000 BUILTIN/ADMINISTRATOR FILENAME.XLS
10/25/2013 10:39 AM 1,332,432 AMERICAS/DOEJ FILENAME2.CSV
11/31/2000 09:54 PM 21,999,999 AMERICAS/DOEF F_I_L_E_N_A_M_E_4.PDF
My goal is to try and add the path of the directory (ex. V:\Word or other directories) in a fixed format at the end of the filename. So Once you see the "Directory V:\word" then you know every line after and up until a new Directory, should show that path at the end of the filename. This would be considered the fifth column.
Here is some code, but I still need to help. I am able to get V:\word at the end of the file, but how do I read the new directory and append that to the end of the lines for all subsequent lines?
private void button1_Click(object sender, EventArgs e)
{
var sbText = new StringBuilder(10000);
string currLine = " Directory of V:\\word ";
try
{
using (StreamReader Reader = new StreamReader(#"C:\V.txt"))
{
while (!Reader.EndOfStream)
{
if (currLine != " Directory of V:\\word ")
{
MessageBox.Show("No Directory");
}
else
{
sbText.AppendLine(Reader.ReadLine() + "V:\\word");
}
}
// When all of the data has been loaded, write it to the text box in one fell swoop
richTextBox1.Text = sbText.ToString();
using (StreamWriter Writer = new StreamWriter(#"C:\NEWFILE.txt"))
{
Writer.WriteLine(sbText);
}
}
}
catch (Exception ex)
{
MessageBox.Show("An error has occured. " + ex.Message);
}
Here's a fairly straight-forward approach--which defines a simple class that represents your data, and parses each line into a class instance. It's efficient, and the results can easily be written to a new file, queried, or displayed:
void Main()
{
var lines = ReadFile();
lines.ToList().ForEach (Console.WriteLine);
}
IEnumerable<Line> ReadFile()
{
using (var reader = new StreamReader(File.OpenRead(#"file.txt")))
{
const string directoryPrefix = " Directory of ";
Regex splittingRegex = new Regex(#"\s+", RegexOptions.Compiled);
string directory = null;
string line;
while ((line = reader.ReadLine()) != null)
{
line = line.TrimEnd();
if (line.StartsWith(directoryPrefix))
{
directory = line.Substring(directoryPrefix.Length);
continue;
}
// The "6" parameter means the regex will split the string into 6 parts at most--leaving the last column (filename) unsplit
var lineParts = splittingRegex.Split(line, 6);
yield return new Line{ Date = lineParts[0], Time = lineParts[1], Period = lineParts[2], Bytes = lineParts[3], User = lineParts[4], Filename = Path.Combine(directory, lineParts[5]) };
}
}
}
// Define other methods and classes here
class Line
{
public string Date{get;set;}
public string Time {get;set;}
public string Period {get;set;}
public string Bytes {get;set;}
public string User {get;set;}
public string Filename {get;set;}
}
Note: This is derived from a couple helper methods for parsing simple text files. One of my earlier revisions include the helper methods, which might be of use to you (but aren't quite suited for this due to the need to remember the directory value).
You're incrementing wCurrLine but never resetting it. I think you want to reset it after each directory?
You're not incrementing totalLines, but then displaying it in label2. I think you should be incrementing it.
How do you check if the input line of text is a directory entry? If your text is consistent as presented, you could check the first letter of each row as it's read in and check if it is the letter 'D'.
You need to AppendLine not Append to put the carriage returns back in
I'm looping through a txt file currently to get server names and check a specific services status and start it if stopped. This works perfectly with my service names stored in my app.config.
What I want to do is also store my file path, file name, timeout, and any other keys I want to put in the app.config down the road.
My issue is when I loop through the app.config currently I only have service names which works perfectly. If I add the other keys that I want to add I obviously will get "Service Not Found".
How do I only pick keys that are "like" "service". I'm naming the keys "service1", 2, 3, etc.
foreach (string key in ConfigurationManager.AppSettings)
{
string value = ConfigurationManager.AppSettings[key];
// Create an instance of StreamReader to read from a file.
// The using statement also closes the StreamReader.
using (StreamReader sr = new StreamReader(txtFilePath + txtFile))
{
String line;
// Read and display lines from the file until the end
// of the file is reached.
while ((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
// Check for lines with semi-colon. If semi-colon at
// line start skip it
if (line.StartsWith(";"))
{
continue;
}
else
{
ServiceController sc = new ServiceController(value, line);
//Create new timeout module.
TimeSpan timeout = new TimeSpan();
//Write current service status to console.
Console.WriteLine(
"The " + value + " service status is currently set to {0}",
sc.Status.ToString()
);
You should move to a named configuration section with elements that you define VS using the AppSetting collection.
I'd follow the recommendations here on how to make a custom section in your config file, and then you're no longer finding items by key, but by section.
I have created an Outlook 2007 add-in in C#.NET 4.0.
I want to read the safe sender list in my C# code.
if (oBoxItem is Outlook.MailItem)
{
Outlook.MailItem miEmail = (Outlook.MailItem)oBoxItem;
OlDefaultFolders f = Outlook.OlDefaultFolders.olFolderContacts;
if (miEmail != null)
{
string body = miEmail.Body;
double score = spamFilterObject.CalculateSpamScore(body);
if (score <= 0.9)
{
miEmail.Move(mfJunkEmail);
}
}
}
So, the above code moves all email to spam, even though they are present in the safe sender list. Thus I want to get the safe sender list so that I can avoid this spam checking.
Could anybody please help me on this?
The Outlook object model doesn't expose these lists (for more or less obvious reasons). The safe sender list can be read straight from the registry at:
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\[PROFILE NAME]\0a0d020000000000c000000000000046\001f0418
This binary registry key contains double-byte characters, separated by a semicolon (;).
The MAPI property mapping onto this registry key is
PR_SPAM_TRUSTED_SENDERS_W, documented here.
Chavan, I assume since this hasn't been updated in over 4 years, you don't need any more information, but this question and the answer helped me find what I was looking for (it was very hard to find) and enabled me to write the code below that may help if you're still looking for an answer.
This code runs in LINQPad, so if you aren't a LINQPad user, remove the .Dump() methods and replace with Console.WriteLine or Debug.WriteLine.
Cheers!
const string valueNameBlocked = "001f0426";
const string valueNameSafe = "001f0418";
// Note: I'm using Office 2013 (15.0) and my profile name is "Outlook"
// You may need to replace the 15.0 or the "Outlook" at the end of your string as needed.
string keyPath = #"Software\Microsoft\Office\15.0\Outlook\Profiles\Outlook";
string subKey = null;
var emptyBytes = new byte[] { };
var semi = new[] { ';' };
string blocked = null, safe = null;
// I found that my subkey under the profile was not the same on different machines,
// so I wrote this block to look for it.
using (var key = Registry.CurrentUser.OpenSubKey(keyPath))
{
var match =
// Get the subkeys and all of their value names
key.GetSubKeyNames().SelectMany(sk =>
{
using (var subkey = key.OpenSubKey(sk))
return subkey.GetValueNames().Select(valueName => new { subkey = sk, valueName });
})
// But only the one that matches Blocked Senders
.FirstOrDefault(sk => valueNameBlocked == sk.valueName);
// If we got one, get the data from the values
if (match != null)
{
// Simultaneously setting subKey string for later while opening the registry key
using (var subkey = key.OpenSubKey(subKey = match.subkey))
{
blocked = Encoding.Unicode.GetString((byte[])subkey.GetValue(valueNameBlocked, emptyBytes));
safe = Encoding.Unicode.GetString((byte[])subkey.GetValue(valueNameSafe, emptyBytes));
}
}
}
// Remove empty items and the null-terminator (sometimes there is one, but not always)
Func<string, List<string>> cleanList = s => s.Split(semi, StringSplitOptions.RemoveEmptyEntries).Where(e => e != "\0").ToList();
// Convert strings to lists (dictionaries might be preferred)
var blockedList = cleanList(blocked).Dump("Blocked Senders");
var safeList = cleanList(safe).Dump("Safe Senders");
byte[] bytes;
// To convert a modified list back to a string for saving:
blocked = string.Join(";", blockedList) + ";\0";
bytes = Encoding.Unicode.GetBytes(blocked);
// Write to the registry
using (var key = Registry.CurrentUser.OpenSubKey(keyPath + '\\' + subKey, true))
key.SetValue(valueNameBlocked, bytes, RegistryValueKind.Binary);
// In LINQPad, this is what I used to view my binary data
string.Join("", bytes.Select(b => b.ToString("x2"))).Dump("Blocked Senders: binary data");
safe = string.Join(";", safeList) + ";\0"; bytes = Encoding.Unicode.GetBytes(safe);
string.Join("", bytes.Select(b => b.ToString("x2"))).Dump("Safe Senders: binary data");
PST and IMAP4 (ost) stores keep the list in the profile section in the registry. Profile section guid is {00020D0A-0000-0000-C000-000000000046}. To access the data directly, you will need to know the Outlook version and the profile name.
Exchange store keeps this data as a part of the server side rule that processes incoming messages on the server side. You can see the rule data in OutlookSpy (I am its author) - go to the Inbox folder, "Associated Contents" tab, find the entry named (PR_RuleMsgName) == "Junk E-mail Rule", double click on it, take a look at the PR_EXTENDED_RULE_CONDITION property.
Outlook Object Model does not expose Junk mail settings. If using Redemption (I am also its author) is an option, it exposes the RDOJunkEmailOptions.TrustedSenders collection (works both for the PST and Exchange stores):
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set Store = Session.Stores.DefaultStore
set TrustedSenders = Store.JunkEmailOptions.TrustedSenders
for each v in TrustedSenders
debug.print v
next
I need to add a custom activity to the default workflow template to increase assembly versions at the earliest point possible in the build process.
What I would like to achieve is to create and map the exact same workspace (that is be created further down in the workflow) inside my custom activity so that I can check out an xml file, increase the version number held within, write it back to the xml file and check the xml file back in.
I'm aware that this workspace will be created later on in the workflow but that will be too late in the build process for what I'm trying to achieve, so instead of moving any of the activities or duplicating them in a position above my custom activity (this should be ok as this workspace will be deleted and recreated again later)
I think the details I need are the BuildDirectory, WorkspaceName and SourcesDirectory. Can anyone tell me how to achieve the creation of the workspace or how obtain this data in code?
the build will be carried out on a build server, and I am using TFS 2010 and c#.
Thanks in advance
I followed the series of blog articles by Ewald Hofman as a primer and created a custom activity that does the check-out, update and check-in of a GlobalAssemblyInfo file that I parse the current version from. My task is inserted at the top of the "Update Drop Location" which is right after it does the "Get the build" portion of the workflow. I just use require the IBuildDetail and a File Mask as arguments from which you can pull out the VersionControlServer to be able to access TFS. My code is below:
protected override string Execute(CodeActivityContext context)
{
// Obtain the runtime value of the input arguments.
string assemblyInfoFileMask = context.GetValue(AssemblyInfoFileMask);
IBuildDetail buildDetail = context.GetValue(BuildDetail);
var workspace = buildDetail.BuildDefinition.Workspace;
var versionControl = buildDetail.BuildServer.TeamProjectCollection.GetService<VersionControlServer>();
Regex regex = new Regex(AttributeKey + VersionRegex);
// Iterate of the folder mappings in the workspace and find the AssemblyInfo files
// that match the mask.
foreach (var folder in workspace.Mappings)
{
string path = Path.Combine(folder.ServerItem, assemblyInfoFileMask);
context.TrackBuildMessage(string.Format("Checking for file: {0}", path));
ItemSet itemSet = versionControl.GetItems(path, RecursionType.Full);
foreach (Item item in itemSet.Items)
{
context.TrackBuildMessage(string.Format("Download {0}", item.ServerItem));
string localFile = Path.GetTempFileName();
try
{
// Download the file and try to extract the version.
item.DownloadFile(localFile);
string text = File.ReadAllText(localFile);
Match match = regex.Match(text);
if (match.Success)
{
string versionNumber = match.Value.Substring(AttributeKey.Length + 2, match.Value.Length - AttributeKey.Length - 4);
Version version = new Version(versionNumber);
Version newVersion = new Version(version.Major, version.Minor, version.Build + 1, version.Revision);
context.TrackBuildMessage(string.Format("Version found {0}", newVersion));
return newVersion.ToString();
}
}
finally
{
File.Delete(localFile);
}
}
}
return null;
}