不带 "run as administrator" 导出事件日志 (.evtx)

Export Event Log (.evtx) without "run as administrator"

问题:是否可以在非"run as administrator"进程中导出事件日志?

我正在遵循 https://msdn.microsoft.com/en-us/library/bb671203(v=vs.90).aspx

中的示例代码
using (var els = new EventLogSession())
{
    els.ExportLogAndMessages("Security", PathType.LogName, "*", @"c:\temp\security.evtx");
}

当我 运行 使用 "run as administrator" 的进程时,此代码 运行 成功,但当不是“运行 作为管理员时失败

System.UnauthorizedAccessException: "Attempted to perform an unauthorized operation."

使用类似的代码访问我的应用程序的事件日志

using (var els = new EventLogSession())
{
    els.ExportLogAndMessages("MyAppLog", PathType.LogName, "*", @"c:\temp\myapplog.evtx");
}

我得到类似的结果,除了例外不同:

System.Diagnostics.Eventing.Reader.EventLogException: "The directory name is invalid"

我是不是做错了什么,或者是否有不同的方法可以让我在不需要管理员权限的情况下将事件日志导出到 .evtx 文件?

备注:

使用 pinvoke.net 上显示的方法无需我的自定义应用程序日志的管理员权限(即上例中的 MyAppLog)。这不适用于上面显示的 Security 日志示例(但我相信这是有意的):

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr OpenEventLog(string UNCServerName, string sourceName);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool BackupEventLog(IntPtr hEventLog, string backupFile);

[DllImport("advapi32.dll", SetLastError = true)]
static extern bool CloseEventLog(IntPtr hEventLog);

void SaveLog(string eventLogName, string destinationDirectory)
{
    string exportedEventLogFileName = Path.Combine(destinationDirectory, eventLogName + ".evtx");

    IntPtr logHandle = OpenEventLog(Environment.MachineName, eventLogName);

    if (IntPtr.Zero != logHandle)
    {
       bool retValue = BackupEventLog(logHandle, exportedEventLogFileName);
       //If false, notify.
       CloseEventLog(logHandle);
    }
}

Question: Is it possible to export an event log in a process not "run as administrator"?

可以,但前提是您有权访问要导出的事件日志。

不过,你的问题似乎更像是

Why can't I export my application's event log using EventLogSession? An EventLogException is thrown with the message "The directory name is invalid".

查看 EventLogSession you can see that the call to ExportLogAndMessages will call the native function EvtExportLog. If this function fails the error code is retrieved by calling GetLastError. This native Windows error code is then mapped to one of several exceptions 的源代码。

如果发生以下任何错误,将抛出您遇到的异常:

  • ERROR_FILE_NOT_FOUND (2): 系统找不到指定的文件。
  • ERROR_PATH_NOT_FOUND (3): 系统找不到指定的路径。
  • ERROR_EVT_CHANNEL_NOT_FOUND (15007): 找不到指定频道。检查通道配置。
  • ERROR_EVT_MESSAGE_NOT_FOUND (15027): 消息资源存在但在 string/message table.
  • 中找不到消息
  • ERROR_EVT_MESSAGE_ID_NOT_FOUND (15028): 找不到所需消息的消息 ID。
  • ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND (15002): 在资源中找不到发布者元数据。

如果您指定了错误的事件日志名称,那么 ERROR_EVT_CHANNEL_NOT_FOUND 就是您遇到的错误。我猜这是你的问题。

但是,您可以自己调用 EvtExportLog 并检查本机错误代码以更好地理解调用失败的原因:

[DllImport("kernel32.dll")]
static extern uint GetLastError();

[DllImport("wevtapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EvtExportLog(IntPtr session, string channelPath, string query, string targetFilePath, int flags);

var success = EvtExportLog(IntPtr.Zero, "MyAppLog", "*", @"c:\temp\myapplog.evtx", 1);
if (!success)
{
    var error = GetLastError();
    Console.WriteLine(error);
}

本机错误代码应该可以清楚地指示根本问题是什么。

这有点旧了,但我在尝试解决同样的问题时又回到了它好几次。如果不提供管理员凭据,我不知道如何使用 EventLogSession

但是,Windows 命令 wevtutil 将允许您在没有管理员权限的情况下导出到 evtx 文件。例如,命令 window 中的 运行ning wevtutil epl Application Downloads\export-Application.evtx 将导出应用程序事件日志。

从C#程序到运行,你可以使用这个方法:

/// <summary>
/// Run wevtutil with the given parameters.
/// </summary>
/// <param name="programPath">Path to wevtutil</param>
/// <param name="programParameters">wevutil parameters</param>
/// <returns></returns>
/// <remarks>
private static (string info, string err) RunWevtUtil(string programPath, string programParameters)
{
    var process = new Process
    {
        StartInfo =
        {
            FileName = programPath,
            Arguments = programParameters,
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true
        }
    };

    process.Start();
    var outputData = process.StandardOutput.ReadToEnd();
    var errorData = process.StandardError.ReadToEnd();
    process.WaitForExit();
    return (outputData, errorData);
}

对于 programPath,请提供 wevtutil 的完整路径,通常为 @"C:\Windows\System32\wevtutil.exe"。对于 programParameters,您可以使用 @"epl Application Downloads\export-Application.evtx"。它 returns 一个字符串元组,提供标准和错误输出。

您可以使用Windows命令行来测试您的参数,然后在程序中使用它们。