Salvataggio di eventi in un file di log
Per salvare gli eventi da un canale a un file di log, chiamare la funzione EvtClearLog o EvtExportLog . La funzione EvtClearLog copia gli eventi nel file di log e li elimina dal canale. La funzione EvtExportLog copia anche gli eventi nel file di log, ma non li elimina dal canale. Per cancellare un canale, l'utente deve disporre delle autorizzazioni Lettura e Cancella.
È possibile eseguire query sugli eventi dal file di log creato; Tuttavia, per eseguire il rendering degli eventi, il provider deve essere registrato nel computer. Per eseguire il rendering di eventi da un file di log quando il provider non è registrato nel computer, è necessario chiamare EvtArchiveExportedLog, che copia le risorse dal provider e le aggiunge al file di log. È quindi possibile copiare il file di log in qualsiasi computer ed eseguire correttamente una query ed eseguirne il rendering degli eventi.
Oltre a usare EvtExportLog per copiare gli eventi da un canale, è anche possibile usarlo per registrare nuovamente gli eventi da un file di log a un altro file di log. È anche possibile usarlo per unire eventi da più canali se si utilizza una query XML strutturata, ma non è possibile usarla per unire gli eventi da più file di log.
Nell'esempio seguente viene illustrato come copiare gli eventi da un canale a un file di log. Nell'esempio vengono quindi registrati nuovamente eventi specifici dal file di log appena creato a un nuovo file di log.
#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;
}
Nell'esempio seguente viene illustrato come unire eventi da più canali usando una query XML strutturata. Nell'esempio seguente viene sostituita la routine principale dell'esempio precedente.
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;
}