ログ ファイルへのイベントの保存
チャネルからログ ファイルにイベントを保存するには、 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;
}