Change Log for EventLog Source - c#

Our company just changed our name, and I am rebranding some of the software. One issue I have run into is that we write to the Event log as Company Name.ProductName. Is there a way to change the Log for a Source without deleting and recreating the Source.
I have been able to determine what Log the Source is associated, but am not sure how to change the log over without deleting existing data outside of changing the Product Name which I would rather not do.
if (!System.Diagnostics.EventLog.SourceExists("ProductName"))
{
System.Diagnostics.EventLog.CreateEventSource(
"ProductName", "Company Name");
}
else if (!EventLog.LogNameFromSourceName("ProductName", ".").Equals("Company Name"))
{
// ??? Not sure what to do here ???
}
eventLog.Source = "ProductName";
eventLog.Log = "Company Name";
eventLog.WriteEntry("The Service has been created.");

It turns out that you cannot change the Log that the Source is associated with. You can delete the Source, and create a new one associated with a different log, but the computer will need to be rebooted before the change takes effect.
I decided to just change the Source name enough that it would create a new Source log under the correct Log file.
This information comes partly from here.

Related

Creating previously deleted source in different event log doesnt work

I have been fighting with the Windows Event log for lots of hours with inconsistent behaviour during test of the log4net EventLogAppender and I realized, that the log4net code worked, but my windows event log was the one being unreasonable.
System
OS: Windows 8.1
C#: .Net 4.5, built to x64
Creating the error case
C#: Create Source1 in TestLog1
C#: Write to the log (Works)
Powershell: Removing the log using powershell
C# Create Source1 in TestLog2 (Different log)
C# Write to the log <= This shows no log entries in TestLog2!
I have made a complete step-by-step guide to recreate the problem:
1: Create a new source in a new log and write to it
Code executed:
EventLog.CreateEventSource(source: "TestSource1", logName: "TestLog1");
EventLog myLog = new EventLog();
myLog.Source = "TestSource1";
myLog.WriteEntry("This is a message");
List logs using powershell-command:
Get-EventLog -LogName *
This will correctly list all logs, including TestLog1 containing 1 log entry.
I can also get the log entries by using this powershell command:
GetEventLog -LogName "TestLog1"
This shows me the single log message in the log.
2: Delete the event log using powershell
Powershell command:
Remove-EventLog -LogName "TestLog1"
Listing all logs now shows, that the log has actually been deleted. Powershell command again:
Get-EventLog -LogName *
3: Create the source again, but in another log this time
Code executed:
EventLog.CreateEventSource(source: "TestSource1", logName: "TestLog2"); // New log name
EventLog myLog = new EventLog();
myLog.Source = "TestSource1";
myLog.WriteEntry("This is a message");
Result:
The log appears in powershell when listing all logs
The log does not contain any entry
Using Get-EventLog "TestLog2" throws and exception even though it appears in the log-list
Deleting the log in powershell using remove-eventlog -logName "TestLog2" somehow still works.
It seems that in some cases, the logs seems to exist, but in others it doesnt.
A: Is this a known bug or what is wrong with my scenario?
B: How can I clean up my existing mess if sources somehow still exist pointing at the old log? (If thats the case, that is)
EDIT: I even tried the following C# code to delete the source first and then the log, but the result is the same:
var source = "TestSource6";
var logName1 = "Testlog5";
var logName2 = "Testlog6";
EventLog.CreateEventSource(source: source, logName: logName1);
new EventLog() { Source = source }.WriteEntry("This is a message in log " + logName1);
EventLog.DeleteEventSource(source:source);
EventLog.Delete(logName:logName1);
EventLog.CreateEventSource(source: source, logName: logName2);
new EventLog() { Source = source }.WriteEntry("This is a message" + logName2);
Unfortunately you can't re-register an event source "back to back". It's one of the (many) reasons installers often ask to restart the computer.
From MSDN:
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.
EventLog.CreateEventSource Method (String, String)
For fixing the issue, I would recommend not deleting the event source unless the product is uninstalled. Just stop using Log1 and start using Log2, without deleting and recreating. When you go to use any log, you could use something similar to this:
if (!EventLog.SourceExists(source, log))
{
EventLog.CreateSource(source, log)
}
And simply leave the source where it is, until you uninstall the product. If you're using InstallShield, it should automatically detect a restart is required and ask the user to do so.

Event Creation is not working

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.

Checking event entries/writing to event log only once

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.

Directory Permission Watcher in c#

I have created the program which is monitoring a directory (e.g. \\server\share\folderXYZ) for changed events (like created, deleted, renamed and permission changes). I also got the notification if anything changed but I can't get exact details what has changed.
For example I have changed the permission for above directory from folder properties (Properties -> Security -> Edit ->Add new user or group or change permission for user and groups). File system watcher give notification if something changed but I can't get other details like:
For which user permission has changed?
Who changed the user permissions?
If any new group has been added(need to get all users in the group if new group added)?
If any new user is added to group and who added and need to get added user details?
If any user or group is removed than removed group or user details?
If any permission is added or changed for user than what permission are added or changed?
If any permission are changed for group than what permission changed?
Example Scenarios:
Action: At 11am, the Admin added User A to Trainees (Existing group)
Expected Result:
Access to \\server\share\folderXYZ changed: User A now has Read access, given by Admin at 11am, because he is now member of Trainees, which has Read Access.
Hope question is clear. I have done lots of search and couldn't find the solution. Please let me know if any API or Service available or any alternatives available?
-Thanks
The way to get the information you want is to use Windows Security Auditing, esp. since you want to know who made a change, not just what the change was.
The following code (and settings), produce output like this:
11-07-2011 17:43:10: 'Fujitsu\Grynn' changed security descriptor on file 'C:\Users\Grynn\Documents\ExcelTools\test.txt' from
'D:AI(A;;0x1200a9;;;BU)(A;ID;FA;;;S-1-5-21-559386011-2179397067-1987725642-1000)(A;ID;FA;;;SY)(A;ID;FA;;;BA)'
to
'D:ARAI(A;ID;FA;;;S-1-5-21-559386011-2179397067-1987725642-1000)(A;ID;FA;;;SY)(A;ID;FA;;;BA)'
using 'C:\Windows\explorer.exe'
12-07-2011 17:55:10: 'Fujitsu\Grynn' changed security descriptor on file 'C:\Users\Grynn\Documents\ExcelTools\test.txt' from
'D:AI(A;ID;FA;;;S-1-5-21-559386011-2179397067-1987725642-1000)(A;ID;FA;;;SY)(A;ID;FA;;;BA)'
to
'D:ARAI(D;;FA;;;S-1-5-21-559386011-2179397067-1987725642-1001)(A;ID;FA;;;S-1-5-21-559386011-2179397067-1987725642-1000)(A;ID;FA;;;SY)(A;ID;FA;;;BA)'
using 'C:\Windows\explorer.exe'
Turning on Auditing has 2 steps:
1. Use gpedit.msc to turn on "Audit Object access"
2. Modify "Auditing" for the folder you want to watch
Now whenever a File System Change event occurs (or via polling) query the security event log.
Code to query 'Security' event log:
var props = new EventLogPropertySelector(new string[] {
"Event/System/TimeCreated/#SystemTime",
"Event/EventData/Data[#Name='SubjectDomainName']",
"Event/EventData/Data[#Name='SubjectUserName']",
"Event/EventData/Data[#Name='ObjectName']",
"Event/EventData/Data[#Name='OldSd']",
"Event/EventData/Data[#Name='NewSd']",
"Event/EventData/Data[#Name='ProcessName']" });
using (var session = new System.Diagnostics.Eventing.Reader.EventLogSession())
{
//4670 == Permissions on an object were changed
var q = new EventLogQuery("Security", PathType.LogName, "*[System[(EventID=4670)]]");
q.Session = session;
EventLogReader rdr = new EventLogReader(q);
for (EventRecord eventInstance = rdr.ReadEvent();
null != eventInstance; eventInstance = rdr.ReadEvent())
{
var elr = ((EventLogRecord)eventInstance);
Console.WriteLine(
"{0}: '{1}\\{2}' changed security descriptor on file '{3}' from \n'{4}' \nto \n'{5}' \nusing '{6}'\n----\n",
elr.GetPropertyValues(props).ToArray());
}
}
From what i know/been reading, FileSystemWatcher can only tell you the file that was affected along with the change type only.
One way to go is for you to maintain a cache of the file attributes you're interested in, an in the presence of an event notifying a change, you query the cache to get the changes made and update it as necessary.

Checking Event Log writing Permissions without writing an entry

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.

Categories

Resources