I’ve been having some problems with writing to a custom event log as well as the standard ‘Application’ event log where it failed with the following error :
Stack Trace:
[Win32Exception (0x80004005): Access is denied]
[InvalidOperationException: Cannot open log for source 'Application'. You may not have write access.]
System.Diagnostics.EventLog.OpenForWrite(String currentMachineName) +1008783
System.Diagnostics.EventLog.InternalWriteEvent(UInt32 eventID, UInt16 category, EventLogEntryType type, String[] strings, Byte[] rawData, String currentMachineName) +216
System.Diagnostics.EventLog.WriteEntry(String message, EventLogEntryType type, Int32 eventID, Int16 category, Byte[] rawData) +264
System.Diagnostics.EventLog.WriteEntry(String source, String message, EventLogEntryType type, Int32 eventID, Int16 category, Byte[] rawData) +87
System.Diagnostics.EventLog.WriteEntry(String source, String message, EventLogEntryType type) +14
ASP.test_testeventlogaccess_aspx.WriteToApplication(Object sender, EventArgs e) in c:\Inetpub\wwwroot\connect\Test\TestEventLogAccess.aspx:20
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +111
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +110
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1565
What made this harder to figure was it worked in one environment but not another! The difference was impersonation was turned on in the web.config for the failing web site :
<system.web> <identity impersonate="true" /> </system.web>
This meant that the user being used to access the event log was not the AppPool identity but rather the ASP.NET IUSR_ identity (which has not been overridden with the optional username/password attributes above in the config above.)
Microsoft has a knowledge base article describing how to configure event log permissions but there were two extra steps I had to perform before I could add the IUSR identity to the event log permissions :
Fetching the SID for an account
The SDDL string that needs to be added according to the knowledge base article referenced above requires the SID for the IUSR account. There are a couple of ways to do this listed below. Either script block should be saved to a .vbs file and run as a parameter to cscript.exe from a command line :
strComputer = "." Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") Set objAccount = objWMIService.Get("Win32_UserAccount.Name='IUSR_<COMPUTER NAME>',Domain='<COMPUTER NAME>'") Wscript.Echo objAccount.SID On Error Resume Next strComputer = "." Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") Set colItems = objWMIService.ExecQuery("Select * from Win32_UserAccount",,48) For Each objItem in colItems Wscript.Echo "AccountType: " & objItem.AccountType Wscript.Echo "Caption: " & objItem.Caption Wscript.Echo "Description: " & objItem.Description Wscript.Echo "Disabled: " & objItem.Disabled Wscript.Echo "Domain: " & objItem.Domain Wscript.Echo "FullName: " & objItem.FullName Wscript.Echo "InstallDate: " & objItem.InstallDate Wscript.Echo "Lockout: " & objItem.Lockout Wscript.Echo "Name: " & objItem.Name Wscript.Echo "PasswordChangeable: " & objItem.PasswordChangeable Wscript.Echo "PasswordExpires: " & objItem.PasswordExpires Wscript.Echo "PasswordRequired: " & objItem.PasswordRequired Wscript.Echo "SID: " & objItem.SID Wscript.Echo "SIDType: " & objItem.SIDType Wscript.Echo "Status: " & objItem.Status Next
Remove the IUSR Identity from the Guest Users Group
The last modification which is not mentioned in the knowledge base article is that the Guest Users group is already explicitly denied access to the event log (at least on my Windows Server 2003 machine) and therefore adding the SID for this account will not have an account. To solve this I removed the IUSR account from the Guest Users group and everything worked.
Debugging
As an aside to be able to test and debug this on both a production and test server I created an .aspx file with no code-behind with the following code :
<%@ Page Language="C#" %> <%@ Import Namespace="System.Diagnostics"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Test Event Log Access</title> <script runat="server"> protected void WriteToMyEventLog(object sender, EventArgs e) { EventLog.WriteEntry("MyEventLog", "This is a test", EventLogEntryType.Error); } protected void WriteToApplication(object sender, EventArgs e) { EventLog.WriteEntry("Application", "This is a test", EventLogEntryType.Error); } </script> </head> <body> <form id="form" runat="server"> <div> <asp:Button runat="server" ID="btnWriteToMyEventLog" Text="Write to My Event Log" OnClick="WriteToMyEventLog" /> <asp:Button runat="server" ID="btnWriteToApplication" Text="Write to Application" OnClick="WriteToApplication" /> </div> </form> </body> </html>

vbscript files are so yesterday! Here’s a link to a ScriptingGuy blog article that shows how to do the same thing using a PowerShell script:
http://blogs.technet.com/b/heyscriptingguy/archive/2010/10/11/use-wmi-and-powershell-to-get-a-user-s-sid.aspx
Comment by Ian — March 29, 2011 @ 9:29 pm
I do like Powershell… I’ve even given a training course before now but if it’s not on the server it’s so much easier to ‘get the job done’ with my old favourite batch files, oh, and yucky vbscript of course.
Comment by philiphendry — March 30, 2011 @ 8:53 am