I need to check if a user has write permissions for the event log. My solution right now is to write a test message in the log and delete it afterwards (so that the log does not get messed up, as the check for permissions is called often (every 3-5 Mins.) by some 'Healthcheck'-service:
const string log = "MyApplicationLog";
const string source = "PermissionCheck";
EventLog evLog;
try
{
if (!EventLog.SourceExists(source))
{
EventLog.CreateEventSource(source, log);
}
evLog = new EventLog();
evLog.Source = source;
evLog.WriteEntry("PermissionCheck Test Message");
return true;
}
finally
{
//remove the check messages:
if (EventLog.Exists(log))
{
EventLog.Delete(log);
}
}
Is there any possibility to check the permissions without actually writing a log entry?
Thank you in advance,
ElKunzo
Yes, AFAIK, using CAS. Decorate the required member/s with the EventLogPermission attribute, from there you can control whether you must have access, only desired and so forth.
This may well entail a little further adventure in CAS itself, however, if you're unfamiliar.
MSDN Link.
Related
I'm using the OnEntryWritten event in order to get events from the event log when they are fired.
The problem I started to see today is that some messages come with parameters unset.
For example:
The Windows Filtering Platform has permitted a bind to a local port. Application Information: Process ID:9852 Application Name:\device\harddiskvolume7\program files (x86)\google\chrome\application\chrome.exe Network Information: Source Address::: Source Port:51714 Protocol:17 Filter Information: Filter Run-Time ID:0 Layer Name:%%14608 Layer Run-Time ID:38
You can see the %%14608 parameter. This comes with a value if I see the same log in the Event Viewer.
I'm running a windows service as LocalSystem, so I don't know if this is a permission issue or this technology is not useful at all.
I have tried the rest offered on C# and they also don't meet my requirements.
UPDATE: this is the code I'm using to read the events.
1) First I subscribe to the corresponding Event log:
private void Subscribe()
{
_eventLog.EnableRaisingEvents = true;
var callbackFunction = new EntryWrittenEventHandler(OnEntryWritten);
_eventLog.EntryWritten += callbackFunction;
// Save a reference for callbackFunction
_eventHandler = callbackFunction;
}
2) Then on the callback method, I read data from the message:
public void OnEntryWritten(Object source, EntryWrittenEventArgs entryArgs)
{
// When overwrite policy is enabled, this will trigger for all elements when it starts writing new ones
try
{
var entry = entryArgs.Entry;
var timeWritten = entry.TimeWritten;
// This comes with %% values depending on the log
string message = entry.Message;
}
catch(Exception ex)
{
...
}
}
3) The event log variable is simply initialized as:
var eventLog = EventLog.GetEventLogs().FirstOrDefault(el => el.Log.Equals(logName, StringComparison.OrdinalIgnoreCase));
I need some help on this, honestly I don't know what else to try.
UPDATE
I'm adding some images here so everybody can understand the situation a little bit better. To be honest, it looks like there's no solution but to implement a dictionary and replace manually the required values, which appear to be always constants.
This is what I see on the Event Viewer for a given Event ID:
This is what I see on my program when I read that entry:
You can clearly see that the following values:
"Machine key." (Key type)
"Read persisted key from file." (Operation)
Are coming unmapped in the ReplacementStrings and the Message properties as: %%2499 and %%2458
This is the message value I get on the program:
"Key file operation.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tMyAccount$\r\n\tAccount Domain:\t\tWORKGROUP\r\n\tLogon ID:\t\t0x3e7\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t6644\r\n\tProcess Creation Time:\t2019-04-03T12:17:24.587994400Z\r\n\r\nCryptographic Parameters:\r\n\tProvider Name:\tMicrosoft Software Key Storage Provider\r\n\tAlgorithm Name:\tUNKNOWN\r\n\tKey Name:\t816339d2-c476-4f1e-bc40-954f0aa0f851\r\n\tKey Type:\t%%2499\r\n\r\nKey File Operation Information:\r\n\tFile Path:\tC:\ProgramData\Microsoft\Crypto\Keys\6d55a45fd69327293e9ed3e7930f4565_5663a8bb-2d1d-4c0d-90c1-624beddabe9c\r\n\tOperation:\t%%2458\r\n\tReturn Code:\t0x0"
What can be done here? There also nothing in entry.Data that might help me out to obtain both values.
No, I believe you're mistaken, sorry that this answer is too late. I found a similar event that was raised by chrome and evaluated if there's anything missed by the event handler. There wasn't anything missed. The message I got in my console output exactly matched what I saw in my Event Viewer.
A better solution would be to
Use entry.Data to get the complete data instead of entry.Message
entry.Data will return a byte[] which you can convert to a string. Here's the link to all properties that an entry will have.
I have created a simple Windows service, following these youtube videos:
https://www.youtube.com/watch?v=cp2aFNtcZfk.
This works, so long as I don't try to do any logging. If I call my logging function:
public static void LogMsg(LogMsgTypes msgType, string msg)
{
string path = AppDomain.CurrentDomain.BaseDirectory;
string logFileName = string.Format("{0}Recalculator{1:yyyyMMdd}.log",path, DateTime.Now);
var file = System.IO.File.AppendText(logFileName);
file.WriteLine(string.Format("{0} {1,-9} : {2}", DateTime.Now.ToString(), msgType, msg));
file.Close();
}
then the service crashes and I get an Unauthorized Access Exception error in the Windows Event Log. I know I should be logging to the Event Log anyway, but I gather I will have to create the source manually first and I would really like to be able to write to a file if possible. On the youtube tutorial I am following, the guy gets no errors at all.
I think the correct answer is probably that I should do it 'right' by creating a source in the Windows Event Log and then writing to there instead of to a custom log file.
For now, I have just installed the service to run under Local System.
I have source "Source401" used for log "Log401". I need to use this source for "Log402" log and delete the log "Log401". (If we can rename “Log401” as “Log402” that is also fine. But all this need to be done programmatically)
With the code below, I am getting the following exception. What is the best way to achieve it?
Source Source401 already exists on the local computer.
Note: When I delete the old log, it is working fine. But the events are not getting created.
UPDATE
From MSDN
The operating system stores event logs as files. When you use EventLogInstaller or CreateEventSource to create a new event log, the associated file is stored in the %SystemRoot%\System32\Config directory on the specified computer. The file name is set by appending the first 8 characters of the Log property with the ".evt" file name extension.
The source must be unique on the local computer; a new source name cannot match an existing source name or an existing event log name. Each source can write to only one event log at a time; however, your application can use multiple sources to write to multiple event logs.
CODE
string source = "Source401";
string logName = "Log402";
string oldLogName = "Log401";
string eventName = "Sample Event";
string machineName = ".";
if (!EventLog.Exists(logName, machineName))
{
////Delete old log
//if (EventLog.Exists(oldLogName, machineName))
//{
// EventLog.Delete(oldLogName, machineName);
//}
//Create Source for the Log
EventLog.CreateEventSource(source, logName, machineName);
//Create Event
EventLog eventLog = new EventLog(logName, machineName, source);
eventLog.WriteEntry(eventName);
try
{
eventLog.WriteEntry(eventName, EventLogEntryType.Warning, 234, (short)3);
}
catch (Exception exception)
{
int x = 0;
}
The exception is telling you exactly what the problem is. The event source named "Source401" already exists. You're deleting the old event log, "Log401", but you're not deleting the event source.
As the documentation says:
The operating system stores event logs as files. When you use EventLogInstaller or CreateEventSource to create a new event log, the associated file is stored in the %SystemRoot%\System32\Config directory on the specified computer. The file name is set by appending the first 8 characters of the Log property with the ".evt" file name extension.
The source must be unique on the local computer; a new source name cannot match an existing source name or an existing event log name. Each source can write to only one event log at a time;
Also, this little nugget:
If a source has already been mapped to a log and you remap it to a new log, you must restart the computer for the changes to take effect.
In addition, you might want to consider this, also from the documentation:
Create the new event source during the installation of your application. This allows time for the operating system to refresh its list of registered event sources and their configuration. If the operating system has not refreshed its list of event sources, and you attempt to write an event with the new source, the write operation will fail
Finally, the CreateEventSource method you're calling is marked obsolete, and has been since .NET 2.0. There's usually a good reason for methods to be marked obsolete. You should be calling CreateEventSource(EventSourceCreationData).
I think you need to re-think the way you're using event logs. Your application shouldn't be creating and deleting logs that way. It's not how they're intended to be used.
How do i read the last entered event log or is there any other way to limit to write only once the same event? This piece of code will help, but is there any other approach available?
EventLog eventLog;
eventLog = new EventLog();
eventLog.Log = eventLogName;
eventLog.Source = sourceName;
foreach (EventLogEntry log in eventLog.Entries)
{
//log.Source - do your stuff
}
There is an excellent article on Reading and Writing to the Event Log.
Use the Entries member when reading from the event log.
Because the property is read-only, you cannot modify an entry or write
to the log using Entries. Instead, specify a Source and call
WriteEntry to write a new log entry. You can use Entries to count the
number of entries in the event log, and view each EventLogEntry in the
collection. Use the indexed Item member to retrieve information about
a specific entry, such as Message, Category, TimeWritten, or
EntryType.
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.
An important distinction between reading and writing log entries is
that it is not necessary to explicitly call a read method. After the
Log and MachineName are specified, the Entries property is
automatically populated. If you change the value of the Log or
MachineName property, the Entries property is repopulated the next
time you read it.
An example would be:
using System;
using System.Diagnostics;
class MySample{
public static void Main(){
EventLog myLog = new EventLog();
myLog.Log = "MyNewLog";
foreach(EventLogEntry entry in myLog.Entries){
Console.WriteLine("\tEntry: " + entry.Message);
}
}
}
You'll obviously want to create a method that will be able to filter or sort out your request based on certain criteria to help limit your choices. Hopefully this helps.
You may encounter certain permission issues; as they are tied into an Administrator Category with the EventLogPermissionAccess.Administer.
The information provided is directly from Microsoft here.
I'm trying to get my .Net Windows Service to right to a custom event log. I'm using EventLogInstaller to create the event log and source when the application is installed. I read here that it takes a while for Windows to register the source so they reccomend you restart the application before trying to write to the log.
As this is a Windows Service I didn't want to have to force a computer restart or get the user to manually start the service up, so I use this code to wait for the log to exist and then start the service automatically.
while (!(EventLog.Exists("ManageIT") || EventLog.SourceExists("ManageIT Client Service")))
{
Thread.Sleep(1000);
}
System.ServiceProcess.ServiceController controller = new System.ServiceProcess.ServiceController("ManageIT.Client.Service");
controller.Start();
My problem is that events from the service are still written to the Application Log and although I can see my custom log in the Registry Editor it does not show up in the Windows 7 Event Viewer.
Any help will be much appreciated.
By default when a service is installed, the source gets associated with the Application Log.
If we change this association at a later point, the system needs a restart.
We can however prevent the association of the service with the application log, by setting autolog property to false in the service class (class which inherits from servicebase) constructor.
http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicebase.autolog.aspx
Try this snippet:
edit - caveat: if the user running the code does not have administrator rights, this will throw an exception. Since this is the case (and if the user will not have these rights) best practices should be to assume the log exists, and simply write to it. see: The source was not found, but some or all event logs could not be searched
if (!EventLog.SourceExists("MyApplicationEventLog"))
{
EventSourceCreationData eventSourceData = new EventSourceCreationData("MyApplicationEventLog", "MyApplicationEventLog");
EventLog.CreateEventSource(eventSourceData);
}
using (EventLog myLogger = new EventLog("MyApplicationEventLog", ".", "MyApplicationEventLog"))
{
myLogger.WriteEntry("Error message", EventLogEntryType.Error);
myLogger.WriteEntry("Info message", EventLogEntryType.Information);
}
It sounds like you are writing to the event log like this:
EventLog.WriteEntry("Source", "Message");
This will write to the application log.
If you use the code in simons post with the creation of myLogger, you can specify the name of the Log.
I did something like this:
var logName = EventLog.LogNameFromSourceName("MyApp", Environment.MachineName);
//delete the source if it associated with the wrong Log
if (!string.IsNullOrEmpty(logName) & logName != "MyLog")
{
EventLog.DeleteEventSource("MyApp", Environment.MachineName);
}
if (!EventLog.SourceExists("MyApp"))
{
EventLog.CreateEventSource("MyApp", "MyLog");
}