Windows, C#: reading eventlog entries from active AND saved logs - c#

I know that I can read the Security logs of a Windows PC using:
var securityLog = new EventLog("security");
foreach (EventLogEntry entry in securityLog.Entries) {
...
}
The entry item contains all the interesting log fields I expect to see like: InstanceId, Message and others. What I want to do now is read the same things from an event log that was saved to disk as an .evtx file.
I have seen suggestions for using
string xpathQuery = "*";
var eventsQuery = args.Length == 0
? new EventLogQuery("Security", PathType.LogName, xpathQuery)
: new EventLogQuery(args[0], PathType.FilePath, xpathQuery);
using (var eventLogReader = new EventLogReader(eventsQuery)) {
EventLogRecord entry;
while ((entry = (EventLogRecord) eventLogReader.ReadEvent()) != null) {
...
}
}
but the entry in the second version doesn't contain the same members/values as the first example. I totally dig that I am confused and am looking at the problem the wrong way.
How should one go about reading the actual per record content from either an active or saved system log?
Or, can I go from an EventLogRecord to an EventLogEntry? I have not seen that conversion method yet.

Related

Reading local event log?

Here i am trying to read the local system event log using c# using this code-
string eventLogText = "";
try
{
var eventLog = new EventLog("logname", "machinename");
foreach (var entry in eventLog.Entries)
{
eventLogText += entry;
}
}
catch (Exception eg)
{
MessageBox.Show(eg.Message);
}
It is working well, but the problem is, in the variable eventLogText i get only System.Diagnostics.EventLogEntry repeatedly, may be this is very common mistake but i don't know what to do as i am very new to the c# as well as programming too.
Secondly i want to know that if a system is not logged in using Administrator account, in that case reading event log will cause any exception or error and if it will what will be the solution for it ?
Need help.Thanks in advance.
Regarding your first question, you are just adding the variable entry to the string, which is calling the ToString method on that variable. The default implementation of ToString is to return the name of the class. (Hence the repeated System.Diagnostics.EventLogEntryoutput)
You will need to use the members in the EventLogEntry class to retrieve the data you are interested in. For example, this console application will print the source and message of the first 10 entries in the Application event log:
static void Main(string[] args)
{
StringBuilder eventLogText = new StringBuilder();
try
{
var eventLog = new EventLog("Application");
var tenMostRecentEvents = eventLog.Entries
.Cast<EventLogEntry>()
.Reverse()
.Take(10);
foreach (EventLogEntry entry in tenMostRecentEvents)
{
eventLogText.AppendLine(String.Format("{0} - {1}: {2}",
entry.Source,
entry.TimeWritten,
entry.Message));
}
Console.WriteLine(eventLogText.ToString());
}
catch (System.Security.SecurityException ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}
Regarding your second question, your code will need the appropriate permissions to read that event log. For example, if I change the code read the Security event log using this line var eventLog = new EventLog("Security"); I will receive a security exception. You can check this answer for more information
Hope it helps!

webservice (iisexpress) keeps files open

I need to create a sema4 file that restricts other sessions from trying to open/write to a database if another session is already trying to do the same 'transaction' By transaction, in this case make a similar booking that is already 'in progress'.
Here's the code:
HttpSessionState ss = HttpContext.Current.Session;
string sessionID = ss.SessionID;
DirectoryInfo di = new DirectoryInfo(dataDirectory + "Semaphores");
string facilityIDExt = requestedFacilityID.ToString().PadLeft(3, '0');
string sema4File = string.Format("{0}.{1:yyyyMMdd}.{2}", sessionID, RequestedStartDT, facilityIDExt);
sema4FilePath = Path.Combine(di.FullName, sema4File);
File.Create(sema4FilePath);
FileInfo[] fiPaths = di.GetFiles(string.Format("*.{0}", facilityIDExt));
bool bookingInProgress = true;
int waitPeriod = 60;
while (waitPeriod > 0 && bookingInProgress)
{
fiPaths = di.GetFiles(string.Format("*.{0}", facilityIDExt));
bookingInProgress = false;
foreach (FileInfo item in fiPaths)
if (item.Name.Contains(string.Format("{0:yyyyMMdd}.{1}", RequestedStartDT, facilityIDExt)) && item.Name != sema4File)
{
if (item.LastWriteTime > DateTime.Now.AddMinutes(-1))
{
bookingInProgress = true;
break;
}
}
System.Threading.Thread.Sleep(5000);
waitPeriod = waitPeriod - 5;
}
The idea is that the actual booking will take much less than 60 seconds to record in the database however in the meantime, no other booking requests will be permitted.
The problem that I am having is that when I call the following:
if (File.Exists(sema4FilePath))
File.Delete(sema4FilePath);
iisexpress won't delete the file as it is 'in use'. It is 'in use' by iisexpress.
I assume that this will happen with iis as well.
I don't understand why iisexpress keeps the sema4 file open?
How do I get around the 'in use' issue when I want to delete the sema4 file?
When you do this:
File.Create(sema4FilePath);
You get back a FileStream. You should close that to release it. Preferably wrap it into a using:
using (var stream = File.Create(sema4FilePath)) {
// Do you stuff
}
Or just directly close if you don't use the contents:
File.Create(sema4FilePath).Close();

Is there a way to check if a printing process was successful?

I have an application where I need to print a ticket. Each ticket must be unique. The application is windows forms and written entirely in c#. For our application we're using Samsung ML- 2525 laser monochromatic printers.
The flow is basically the following, the operator picks a product/ticket (which is unique) and then it presses a button that does 2 things:
Connects to a database and updates the product as used
Prints the ticket (this is done using System.Drawing and GDI+)
For some reason, every once in a while, the image that needs to be printed is not sent to the printer. It's a rare case, but it happens.
I tried to connect to the printer using Win32_Printer ( http://msdn.microsoft.com/en-us/library/Aa394363 ) but I can't get to get the current printer's state (online, offline, low toner, paper jam, etc). I can only check if the printer exists and that the paper size is installed correctly. I tried code similar to the following but it didn't work
private string MonitorPrintJobWmi()
{
var jobMessage = String.Empty;
var scope = new ManagementScope(ManagementPath.DefaultPath);
scope.Connect();
var selectQuery = new SelectQuery { QueryString = #"select * from Win32_PrintJob" };
var objSearcher = new ManagementObjectSearcher(scope, selectQuery);
var objCollection = objSearcher.Get();
foreach (var job in objCollection)
{
if (job != null)
{
jobMessage += String.Format("{0} \r\n", job["Name"].ToString());
jobMessage += String.Format("{0} \r\n", job["JobId"].ToString());
_jobId = Convert.ToInt32(job["JobId"]);
jobMessage += String.Format("{0} \r\n", job["JobStatus"].ToString());
jobMessage += String.Format("{0} \r\n", job["Status"].ToString());
}
}
return jobMessage;
}
I tried to get an API for the printer but I couldn't get a hold of it. By the way, the printer's software do indicate different errors in the windows toolbar.
My question is if anyone can lead me in the right direction as to how to connect to a printer and check if printing was successful.
Also, it would be helpful if someone know of some other specific printer in which I may accomplish this ie, changing hardware.
Thanks,
To get a list of print queues on the local machine, try PrintServer's GetPrintQueues method.
Once you have an instance of the PrintQueue object associated with the relevant printer, you can use it to access the printer's status (IsOffline, IsPaperOut, etc.). Also, you can use it to get a list of the jobs in the given queue (GetPrintJobInfoCollection) which then will allow you to get job-specific status information (IsInError, IsCompleted, IsBlocked, etc.).
Hope this helps!
After try to print your PrintDocument (System.Drawing.Printing), try to check status of printjobs.
First step: Initialize your printDocument.
Second step: Get your printer Name From System.Drawing.Printing.PrinterSettings.InstalledPrinters.Cast<string>();
And copy it into your printerDocument.PrinterSettings.PrinterName
Third step: Try to print and dispose.
printerDocument.Print();
printerDocument.Dispose();
Last step: Run the check in a Task (do NOT block UI thread).
Task.Run(()=>{
if (!IsPrinterOk(printerDocument.PrinterSettings.PrinterName,checkTimeInMillisec))
{
// failed printing, do something...
}
});
Here is the implementation:
private bool IsPrinterOk(string name,int checkTimeInMillisec)
{
System.Collections.IList value = null;
do
{
//checkTimeInMillisec should be between 2000 and 5000
System.Threading.Thread.Sleep(checkTimeInMillisec);
// or use Timer with Threading.Monitor instead of thread sleep
using (System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_PrintJob WHERE Name like '%" + name + "%'"))
{
value = null;
if (searcher.Get().Count == 0) // Number of pending document.
return true; // return because we haven't got any pending document.
else
{
foreach (System.Management.ManagementObject printer in searcher.Get())
{
value = printer.Properties.Cast<System.Management.PropertyData>().Where(p => p.Name.Equals("Status")).Select(p => p.Value).ToList();
break;
}
}
}
}
while (value.Contains("Printing") || value.Contains("UNKNOWN") || value.Contains("OK"));
return value.Contains("Error") ? false : true;
}
Good luck.

Get Safe sender list in Outlook 2007 C# Add in

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

Read event log in C#

I'm trying to read event logs for my application EventLoggingApp. The problem is reading logs for my single source (EventLoggingApp).
This code read logs for every source. What is the problem? Any advice?
static void ReadEvenLog()
{
string eventLogName = "Application";
string sourceName = "EventLoggingApp";
string machineName = "Tom";
EventLog eventLog = new EventLog();
eventLog.Log = eventLogName;
eventLog.Source = sourceName;
eventLog.MachineName = machineName;
foreach (EventLogEntry log in eventLog.Entries)
{
Console.WriteLine("{0}\n",log.Source);
}
}
Try this:
EventLog log = new EventLog("Security");
var entries = log.Entries.Cast<EventLogEntry>()
.Where(x => x.InstanceId == 4624)
.Select(x => new
{
x.MachineName,
x.Site,
x.Source,
x.Message
}).ToList();
Check out this article on MSDN. You can't read event log entries by source. Only log name matters. Instead you can create separate event log for you application or filter entries by verifying Source property of each entry in foreach loop.
MSDN (1)(2) says that Source is for writing event logs only.
It is not necessary to specify a Source when only reading from a log. You can specify only the Log name and MachineName (server computer name) properties for the EventLog instance. In either case, the Entries member is automatically populated with the event log's list of entries. You can select the appropriate index for an item in this list to read individual entries. (1)
I am not really sure what you were trying to print on the console. If it is the message in each event log entry that you are trying to print, inside the foreach loop you should have this instead:
Console.WriteLine(log.Message + "\n");
If you connect to localhost set MachineName to "."
Check if user has right to read from eventlog

Categories

Resources