7

I've got a library that I use across multiple ClickOnce applications. In the event of an error in this library I would like to write the error to the windows EventLog.

I found a KB article on how but it seems that this requires administrator permissions to search the for the source. Specifically it chokes when trying to search the Security event log.

Is there anyway to work around this and write to the event log in a ClickOnce application? I saw one person trying to write to a known source, but they didn't seem to be able to find a source that was consistently available.

EDIT:

Based on answers here I create an program that's included with my application that I can run on the first run to set up the event source that can get admin privileges. However once the source is created it seems I still cannot write to it.

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        if (!EventLog.SourceExists("ATE"))
        {
            EventLog.CreateEventSource("ATE", "Application");
        }
    }

Is properly creates a source (which is equivalent to the registry edit provided by Yannick Blondeau). When I write to the source in my non-elevated application I receive an new error, but it still doesn't work. The new error is:

Cannot open log for source 'ATE'. You may not have write access.

EDIT 2:

I've now been trying to get it to work through registry edits on the CustomSD key. I tried adding (A;;0x7;;;AU) to give authenticated users full access but it didn't seem to have any effect.

Community
  • 1
  • 1
Fr33dan
  • 4,227
  • 3
  • 35
  • 62

3 Answers3

8

Unfortunately, the event source requires administrative priveledges to be created. However, you don't need admin rights to write to the event log, or read from it.

There are two ways around this.

You add the new event source when you install the application as an administrator.

You create a simple app that you run as an admin to configure your application. This could even be included in the installer.

If you don't have or want an installer, the load the app onto the computer as an admin and run the program once. Your app startup should configure the event source if it isn't already there anyway, right? (Okay, that's three ways.)

This code snippet is from microsoft: http://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog.aspx and is designed to be run as an admin user.

using System;
using System.Diagnostics;
using System.Threading;

class MySample
{
    public static void Main()
    {
        // Create the source, if it does not already exist. 
        if (!EventLog.SourceExists("MySource"))
        {
             //An event log source should not be created and immediately used. 
             //There is a latency time to enable the source, it should be created 
             //prior to executing the application that uses the source. 
             //Execute this sample a second time to use the new source.
             EventLog.CreateEventSource("MySource", "MyNewLog");
             Console.WriteLine("CreatedEventSource");
             Console.WriteLine("Exiting, execute the application a second time to use the source.");
            // The source is created.  Exit the application to allow it to be registered. 
            return;
        }
        // Create an EventLog instance and assign its source.
        EventLog myLog = new EventLog();
        myLog.Source = "MySource";

        // Write an informational entry to the event log.    
        myLog.WriteEntry("Writing to event log.");
    }
}

I know it may not be exactly what you were after, but I reckon it's the only way to do this.

EDIT 1: Added some more code

public class EventLogger
{
    private const string logName = "Application";
    private static string appName = "";
    private static bool sourceExists = false;

    public static string AppName
    {
        get { return appName; }
        set { appName = value; }
    }

    public static void Init(string appName)
    {
        AppName = appName;
        sourceExists = EventLog.SourceExists(AppName);

        if (!sourceExists)
        {
            EventLog.CreateEventSource(AppName, logName);
            sourceExists = true;
        }
    }

    private static void Write(string entry, EventLogEntryType logType, int eventID)
    {
        if (sourceExists)
        {
            EventLog.WriteEntry(AppName, entry, logType, eventID);
        }
    }

    public static void Warning(string entry) { Write(entry, EventLogEntryType.Warning, 200); }
    public static void Warning(string entry, int eventID) { Write(entry, EventLogEntryType.Warning, eventID); }
    public static void Error(string entry) { Write(entry, EventLogEntryType.Error, 300); }
    public static void Error(string entry, int eventID) { Write(entry, EventLogEntryType.Error, eventID); }
    public static void Info(string entry) { Write(entry, EventLogEntryType.Information, 100); }
    public static void Info(string entry, int eventID) { Write(entry, EventLogEntryType.Information, eventID); }
}

This is the way that I have implemented my EventLogger class which is in use in a production application.

If you could post your code we can do a comparison.

One thing that occurs to me is that when I create my source, I use the application name, but stick with the Application logfile. Are you also attempting to create a new logfile. If so check that it is created in the event viewer.

EDIT 2: Impersonate User with a user token value of zero

This is a bit of a stumper.

Try this code, wrapped around the event writing code.

System.Security.Principal.WindowsImpersonationContext wic = System.Security.Principal.WindowsIdentity.Impersonate(IntPtr.Zero);
// your code to write to event log or any to do something which needs elevated permission--
wic.Undo();

I haven't tried this, simply because my code is working, it comes from here: http://sharenotes.wordpress.com/2008/03/18/cannot-open-log-for-source-you-may-not-have-write-access/

John Judd
  • 750
  • 7
  • 22
  • 1
    I think your 3rd idea of loading an app and running it once will have to be my solution as the entire purpose of ClickOnce that it handles deployment and installation. However even if I create the event source in such an application I receive an error when I go to write to it. It says "Cannot open log for source 'MySource'. You may not have write access." This seems like I'm getting closer, but it's not quite there. – Fr33dan Sep 27 '12 at 15:23
  • Did you exit the application before attempting to write? In that code snippet from MS they explicitly state that the log source should not ne created and immediately used as there is a latency period needed to enable the source. – John Judd Sep 27 '12 at 23:17
  • Yes, at the moment I ran the setup application manually to see if it would work so there was 20+ seconds between the source creation and the attempt to write to it. – Fr33dan Oct 01 '12 at 13:10
  • Oh, I didn't see the edit you made after you commented. Well my code for creating the source is in my question, and I try to write to it with `EventLog.WriteEntry("ATE", output);` where `output` is a parameter in the method. See my updated question for the error I receive. – Fr33dan Oct 01 '12 at 14:29
  • Fr33dan, I've added some more info to the answer. Try using impersonation to temporarily raise the user permissions. – John Judd Oct 02 '12 at 02:35
  • Good find, but it didn't work. I'm beginning to think it may just not be possible. – Fr33dan Oct 02 '12 at 13:28
  • It has to be possible because there are applications that use it, including several of mine :-) Have you tried running it on a different computer? I'm wondering if there is an issue with account permissions on your PC. – John Judd Oct 02 '12 at 23:21
  • Well, I thought "that can be it cause I've tried it on 2 computers" but decided to try another just to be sure and it worked. I'd like to know how both my development machine and my sandbox machine got the same problem that doesn't seem to manifest anywhere else but it's most certainly not a programming issue – Fr33dan Oct 03 '12 at 19:27
  • What are the OS versions on each of the machines you tried it on? – John Judd Oct 03 '12 at 23:18
  • Both non-functioning machines are Windows 7, less than 3 months old. The first machine I got it to work on was Windows 2000, but I verified on a forth machine that's on Windows 7 before I reported success here. – Fr33dan Oct 04 '12 at 14:06
  • Okay. I was wondering if it was an XP machine where it worked. MS changed a lot of security permissions with Vista and above and complicated things for a lot of developers. But if you are working on a W7 PC... I think it is the security settings you have on the non-functioning machines, can you try and compare between the two? The only other thing I can suggest at the moment is to create an admin service that acts as a middleman between your app and the event logger, and that's quite a hack! – John Judd Oct 09 '12 at 00:39
  • I experienced exactly the same issue on Windows 7. Even installed / executed using an Administrator account, the ClickOnce app. does not seem to have the privileges required to create the event source. As a temporary fix I've created a console app (much like the one above) which needs to be "Run as Administrator" before the ClickOnce app. can be used. N.B. I'm launching the ClickOnce app using the app-ref file. – Tom Tom Feb 13 '14 at 09:03
2

An alternative approach to this is to download the ClickOnce setup.exe file, right click and run as administrator. Not very satisfactory but seems to work.

0

In the ClickOnce documentation, it is said that if the user running a ClickOnce application is not an administrator, the application will fail writing to the event log.

Full quote:

After a ClickOnce deployment, the application will create an event source if it does not already exist when the application attempts to write an event to the Event log. If the user is not an administrator, the attempt fails and the application will not log any events. In this case, you can create the event source manually.

To create the event source manually, you will have to add an entry in the registry like this one during your deployment process:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\YourApp]
"EventMessageFile"="%SystemRoot%\\Microsoft.NET\\Framework\\v2.0.50727\\EventLogMessages.dll"

This approach will limit the elevation need at the deployment phase.

Yannick Blondeau
  • 9,465
  • 8
  • 52
  • 74
  • 1
    Since ClickOnce handles deployment and installation I would have to figure out another way to run it as an admin. I have created a packaged executable to run code as an administrator. Your registry edit creates the event source, but I still receive the error "Cannot open log for source 'MySource'. You may not have write access." when I try and write to it. – Fr33dan Sep 27 '12 at 15:29