Using custom Event Log Sources on Least Privilege SharePoint Servers
As you will surely be aware, it is best practice to install production SharePoint farms using something called the “least privilege account principle”. This effectively means that each service account in the farm is dedicated to a specific job and has only the minimum rights required in order to do that job. This is best practice as one of many common steps to ensuring your farm is secure, you can read all about it here Plan for administrative and service accounts (Office SharePoint Server).
If you deploy a custom solution on SharePoint that contains some for of error logging, it is likely that you will want to write events to the Windows event log. These events are typically written to the application log under a custom source that matches the name of your solution/application. Typically the custom source is created as part of the code itself and the code to do this is something like the following:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
if (EventLog.SourceExists("MyCustomSource") == false)
{
EventLog.CreateEventSource("MyCustomSource ", "Application");
}
EventLog.WriteEntry("MyCustomSource", "My message", EventLogEntryType.Error);
});
The problem with the above code is that in a least privilege scenario, this will cause an exception because the code will execute under the context of the Application Pool which will not have any local rights on the machine and is not able to create the event source. You may see an error both on-screen and in the logs along the lines of “The source was not found, but some or all event logs could not be searched.”.
To work around this issue, the event log source must be created under the context of an account which does have increased rights on the local machine. There are several ways of doing this, which include:
- Increase the rights of he application pool account. This is bad practice and effectively mitigates the point of using least privilege
- A .net console application which has similar code as shown above but is manually execute as a local administrator account. This is a decent work around, but introduces a separate piece of custom code which is not always ideal.
- A PowerShell script which creates the event source. This is a better option that a custom .net console application, but is still code and not all environments allow Powershell scripts.
- Do not use custom sources and write to an existing one such as ‘Windows SharePoint Services’. This will cause problems because the SharePoint sources have specific message text files and will not accept generic error messages. Therefore if you do this your messages will always be prefixed by "The description for Event ID 0 from source Windows SharePoint Services cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer."
In my projects, i tend to go for the simplest solution and in this case it is very simple. It turns out that Event Log Sources are simply keys in the registry.
All event log sources are stored in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog. In this key there are subkeys for each of the logs (Application, System etc) and a further sub-key for each of the sources in that log. All you need to do is add a key which matches the name of the source you wish to create.
All event log sources need to refer to an ‘EventMessageFile’. These files define the message text that is available for events in that particular source. Typically you’ll want to use the standard .net file which allows any text. To do this you need to add an ‘Expandable String Value’ beneath the key you created for your custom source. The value of this should typically be set to “C:\Windows\Microsoft.NET\Framework\v2.0.50727\EventLogMessages.dll” or “C:\Windows\Microsoft.NET\Framework64\v2.0.50727\EventLogMessages.dll” on 64-bit machines.
Your registry should look something like this:
You can do this manually (on every server in the farm) through something like regedit.,exe or you can create a .reg file which you can simply double click-on to add the registry hive. To create a .reg file, follow these steps:
1. Manually create the registry hive on one mahcine
2. Right-click on the hive (i.e. the key you created beneath HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Application and choose ‘export’
3. Save the file as a .reg file
4. Simply double-click the .reg file on other servers to import the key
5. Reboot the machine (you’ll nee to reboot before you can use your custom source)
Once the source is created, the following code will work perfectly:
EventLog.WriteEntry("MyCustomSource", "My message", EventLogEntryType.Error);
This article was published by
Martin Kearn Senior Consultant Microsoft Consulting Services UK Martin.Kearn@Microsoft.com |
Comments
Anonymous
October 21, 2009
Gr8 ..I was looking for this information since long time ..thanksAnonymous
November 11, 2009
Martin, good article! The concept is broken, as much as I see it ...anything that requires the admins to install manually on every server in the Farm is just wrong. There is too much room for error that way. Just like there's a method in SharePoint to configure the web.config on all servers there's got to be a concept to allow the service accounts of the webapps to also write to the eventlog. jenniferAnonymous
May 09, 2010
Martin, I need to reverse what I said before: simply add the the EventLog source in the code for the FeatureInstalled event of the solution. This event is executed on all WFE and can create the respective registry entry on all servers.