將事件儲存至記錄檔
若要將事件從通道儲存到記錄檔,請呼叫 EvtClearLog 或 EvtExportLog 函式。 EvtClearLog函式會將事件複製到記錄檔,並從通道中刪除事件。 EvtExportLog函式也會將事件複製到記錄檔,但不會從通道中刪除事件。 若要清除通道,使用者必須具有讀取和清除許可權。
您可以從您建立的記錄檔查詢事件;不過,若要轉譯事件,必須在電腦上註冊提供者。 若要在電腦上未註冊提供者時,從記錄檔轉譯事件,您必須呼叫 EvtArchiveExportedLog,該記錄檔會從提供者複製資源,並將其新增至記錄檔。 然後,您可以將記錄檔複製到任何電腦,並成功查詢並轉譯其事件。
除了使用 EvtExportLog 從通道複製事件之外,您也可以使用它將事件從一個記錄檔重新記錄到另一個記錄檔。 如果您使用結構化 XML 查詢,但無法使用它來合併來自多個記錄檔的事件,您也可以使用它來合併來自多個通道的事件。
下列範例示範如何將事件從通道複製到記錄檔。 然後,此範例會將新建立的記錄檔中的特定事件重新記錄到新的記錄檔。
#include <windows.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
#define ARRAY_SIZE 10
DWORD DumpEvents(LPCWSTR pwsLogFile);
DWORD PrintResults(EVT_HANDLE hResults);
DWORD PrintEvent(EVT_HANDLE hEvent);
void main(void)
{
DWORD status = ERROR_SUCCESS;
LPWSTR pPath = L"<path to channel goes here>";
LPWSTR pQuery = NULL;
LPWSTR pTargetLogFile = L".\\log.evtx";
// Export all the events in the specified channel to the target log file.
if (!EvtExportLog(NULL, pPath, pQuery, pTargetLogFile, EvtExportLogChannelPath))
{
wprintf(L"EvtExportLog failed for initial export with %lu.\n", GetLastError());
goto cleanup;
}
// Dump the events from the log file.
wprintf(L"Events from %s log file\n\n", pTargetLogFile);
DumpEvents(pTargetLogFile);
// Create a new log file that will contain all events from the specified
// log file where the event ID is 2.
pPath = L".\\log.evtx";
pQuery = L"Event/System[EventID=2]";
pTargetLogFile = L".\\log2.evtx";
// Export all events from the specified log file that have an ID of 2 and
// write them to a new log file.
if (!EvtExportLog(NULL, pPath, pQuery, pTargetLogFile, EvtExportLogFilePath))
{
wprintf(L"EvtExportLog failed for relog with %lu.\n", GetLastError());
goto cleanup;
}
// Dump the events from the log file.
wprintf(L"\n\n\nEvents from %s log file\n\n", pTargetLogFile);
DumpEvents(pTargetLogFile);
cleanup:
return;
}
// Dump all the events from the log file.
DWORD DumpEvents(LPCWSTR pwsPath)
{
EVT_HANDLE hResults = NULL;
DWORD status = ERROR_SUCCESS;
hResults = EvtQuery(NULL, pwsPath, NULL, EvtQueryFilePath);
if (NULL == hResults)
{
wprintf(L"EvtQuery failed with %lu.\n", status = GetLastError());
goto cleanup;
}
status = PrintResults(hResults);
cleanup:
if (hResults)
EvtClose(hResults);
return status;
}
// Enumerate all the events in the result set.
DWORD PrintResults(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hEvents[ARRAY_SIZE];
DWORD dwReturned = 0;
while (true)
{
// Get a block of events from the result set.
if (!EvtNext(hResults, ARRAY_SIZE, hEvents, INFINITE, 0, &dwReturned))
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
wprintf(L"EvtNext failed with %lu\n", status);
}
goto cleanup;
}
// For each event, call the PrintEvent function which renders the
// event for display. PrintEvent is shown in RenderingEvents.
for (DWORD i = 0; i < dwReturned; i++)
{
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[i])))
{
EvtClose(hEvents[i]);
hEvents[i] = NULL;
}
else
{
goto cleanup;
}
}
}
cleanup:
// Executed only if there was an error.
for (DWORD i = 0; i < dwReturned; i++)
{
if (NULL != hEvents[i])
EvtClose(hEvents[i]);
}
return status;
}
// Print the event as an XML string.
DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
LPWSTR pRenderedContent = NULL;
// The EvtRenderEventXml flag tells EvtRender to render the event as an XML string.
if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pRenderedContent = (LPWSTR)malloc(dwBufferSize);
if (pRenderedContent)
{
EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", GetLastError());
goto cleanup;
}
}
wprintf(L"\n\n%s", pRenderedContent);
cleanup:
if (pRenderedContent)
free(pRenderedContent);
return status;
}
下列範例示範如何使用結構化 XML 查詢,從多個通道合併事件。 此範例會取代上一個範例的主要程式。
void main(void)
{
DWORD status = ERROR_SUCCESS;
LPWSTR pTargetLogFile = L".\\log.evtx";
LPWSTR pQuery = L"<QueryList>"
L" <Query Id='0'>"
L" <Select Path='<path to channel goes here>'>*</Select>"
L" </Query>"
L" <Query Id='1'>"
L" <Select Path='<path to channel goes here>'>*</Select>"
L" </Query>"
L"</QueryList>";
if (!EvtExportLog(NULL, NULL, pQuery, pTargetLogFile, EvtExportLogChannelPath))
{
wprintf(L"EvtExportLog failed with %lu.\n", GetLastError());
goto cleanup;
}
wprintf(L"Events from %s log file\n\n", pTargetLogFile);
DumpEvents(pTargetLogFile);
cleanup:
return;
}