创建源发起的订阅
通过源发起的订阅,可以在事件收集器计算机上定义订阅,而无需定义事件源计算机,然后可以设置多个远程事件源计算机(使用组策略设置)将事件转发到事件收集器计算机。 在本地计算机可以订阅事件并且远程事件源可以转发事件之前,必须将这两台计算机都配置为事件收集和转发。 有关如何配置计算机的详细信息,请参阅设置源发起的订阅。
以下代码示例遵循一系列步骤来创建收集器发起的订阅,其中事件源与事件收集器计算机位于同一域中。
以编程方式创建源发起的订阅
- 通过将订阅名称和访问权限作为参数提供给 EcOpenSubscription 函数来打开订阅。 有关访问权限的详细信息,请参阅 Windows 事件收集器常量。
- 通过调用 EcSetSubscriptionProperty 函数设置订阅的属性。 有关可设置的订阅属性的详细信息,请参阅 EC_SUBSCRIPTION_PROPERTY_ID 枚举。
- 通过调用 EcSaveSubscription 函数保存订阅。
- 通过调用 EcClose 函数关闭订阅。
以下 C++ 示例展示了如何创建源发起的订阅:
#include <windows.h>
#include <iostream>
using namespace std;
#include <string>
#include <xstring>
#include <conio.h>
#include <EvColl.h>
#include <vector>
#include <wincred.h>
#pragma comment(lib, "credui.lib")
#pragma comment(lib, "wecapi.lib")
// Track properties of the Subscription.
typedef struct _SUBSCRIPTION_SOURCE_INITIATED
{
std::wstring Name;
EC_SUBSCRIPTION_TYPE SubscriptionType;
std::wstring Description;
BOOL SubscriptionStatus;
std::wstring URI;
EC_SUBSCRIPTION_CONFIGURATION_MODE ConfigMode;
EC_SUBSCRIPTION_DELIVERY_MODE DeliveryMode;
DWORD MaxItems;
DWORD MaxLatencyTime;
DWORD HeartbeatInerval;
time_t Expires;
std::wstring Query;
BOOL ReadExistingEvents;
std::wstring TransportName;
EC_SUBSCRIPTION_CONTENT_FORMAT ContentFormat;
std::wstring DestinationLog;
std::wstring AllowedSourceNonDomainComputers;
std::wstring AllowedSourceDomainComputers;
} SUBSCRIPTION_SOURCE_INITIATED;
// Subscription Information
DWORD GetProperty(EC_HANDLE hSubscription,
EC_SUBSCRIPTION_PROPERTY_ID propID,
DWORD flags,
std::vector<BYTE>& buffer,
PEC_VARIANT& vProperty);
void __cdecl wmain()
{
LPVOID lpwszBuffer;
DWORD dwRetVal = ERROR_SUCCESS;
EC_HANDLE hSubscription;
EC_VARIANT vPropertyValue;
std::vector<BYTE> buffer;
PEC_VARIANT vProperty = NULL;
SUBSCRIPTION_SOURCE_INITIATED sub;
sub.Name = L"TestSubscription-SourceInitiated";
sub.SubscriptionType = EcSubscriptionTypeSourceInitiated;
sub.Description = L"A subscription that collects events that are published in\n" \
L"the Microsoft-Windows-TaskScheduler/Operational log and forwards them \n" \
L"to the ForwardedEvents log.";
sub.URI = L"http://schemas.microsoft.com/wbem/wsman/1/windows/EventLog";
sub.Query = L"<QueryList>" \
L"<Query Path=\"Microsoft-Windows-TaskScheduler/Operational\">" \
L"<Select>*</Select>" \
L"</Query>" \
L"</QueryList>";
sub.DestinationLog = L"ForwardedEvents";
sub.ConfigMode = EcConfigurationModeCustom;
sub.MaxItems = 5;
sub.MaxLatencyTime = 1000;
sub.HeartbeatInerval = 60000;
sub.DeliveryMode = EcDeliveryModePush;
sub.ContentFormat = EcContentFormatRenderedText;
sub.ReadExistingEvents = true;
sub.SubscriptionStatus = true;
sub.TransportName = L"http";
// This SDDL grants members of the Domain Computers domain group as well
// as members of the Network Service group (for the local forwarder),
// the ability to raise events for this subscription.
sub.AllowedSourceDomainComputers = L"O:NSG:NSD:(A;;GA;;;DC)(A;;GA;;;NS)";
// Step 1: Open the Event Collector subscription.
hSubscription = EcOpenSubscription(sub.Name.c_str(),
EC_READ_ACCESS | EC_WRITE_ACCESS,
EC_CREATE_NEW);
if ( !hSubscription)
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Step 2: Define the subscription properties.
// Set the subscription type property (collector initiated).
vPropertyValue.Type = EcVarTypeUInt32;
vPropertyValue.UInt32Val = sub.SubscriptionType;
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionType,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the Description property that contains a description
// of the subscription.
vPropertyValue.Type = EcVarTypeString;
vPropertyValue.StringVal = sub.Description.c_str();
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionDescription,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the URI property that specifies the URI of all the event sources.
vPropertyValue.Type = EcVarTypeString;
vPropertyValue.StringVal = sub.URI.c_str();
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionURI,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the Query property that defines the query used by the event
// source to select events that are forwarded to the event collector.
vPropertyValue.Type = EcVarTypeString;
vPropertyValue.StringVal = sub.Query.c_str();
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionQuery,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the Log File property that specifies where the forwarded events
// will be stored.
vPropertyValue.Type = EcVarTypeString;
vPropertyValue.StringVal = sub.DestinationLog.c_str();
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionLogFile,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the ConfigurationMode property that specifies the mode in which events
// are delivered.
vPropertyValue.Type = EcVarTypeUInt32;
vPropertyValue.UInt32Val = sub.ConfigMode;
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionConfigurationMode,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// If the Configuration Mode is Custom, set the DeliveryMode, DeliveryMaxItems,
// HeartbeatInterval, and DeliveryMaxLatencyTime properties.
if ( sub.ConfigMode == EcConfigurationModeCustom)
{
// Set the DeliveryMode property that defines how events are delivered.
// Events can be delivered through either a push or pull model.
vPropertyValue.Type = EcVarTypeUInt32;
vPropertyValue.UInt32Val = sub.DeliveryMode;
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionDeliveryMode,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the DeliveryMaxItems property that specifies the maximum number of
// events that can be batched when forwarded from the event sources.
vPropertyValue.Type = EcVarTypeUInt32;
vPropertyValue.UInt32Val = sub.MaxItems;
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionDeliveryMaxItems,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the HeartbeatInterval property that defines the time interval, in
// seconds, that is observed between the heartbeat messages.
vPropertyValue.Type = EcVarTypeUInt32;
vPropertyValue.UInt32Val = sub.HeartbeatInerval;
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionHeartbeatInterval,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the DeliveryMaxLatencyTime property that specifies how long, in
// seconds, the event source should wait before forwarding events.
vPropertyValue.Type = EcVarTypeUInt32;
vPropertyValue.UInt32Val = sub.MaxLatencyTime;
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionDeliveryMaxLatencyTime,
NULL,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
}
// Set the ContentFormat property that specifies the format for the event content.
vPropertyValue.Type = EcVarTypeUInt32;
vPropertyValue.UInt32Val = sub.ContentFormat;
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionContentFormat,
0,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the ReadExistingEvents property that is used to enable or disable whether
// existing events are forwarded.
vPropertyValue.Type = EcVarTypeBoolean;
vPropertyValue.BooleanVal = sub.ReadExistingEvents;
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionReadExistingEvents,
0,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the Enabled property that is used to enable or disable the subscription
// or to obtain the current status of a subscription.
vPropertyValue.Type = EcVarTypeBoolean;
vPropertyValue.BooleanVal = sub.SubscriptionStatus;
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionEnabled,
0,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Set the TransportName property that determines the type of
// transport used by the subscription.
vPropertyValue.Type = EcVarTypeString;
vPropertyValue.StringVal = sub.TransportName.c_str();
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionTransportName,
0,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Required:
// Set the AllowedSourceDomainComputers property to the specified SDDL.
vPropertyValue.Type = EcVarTypeString;
vPropertyValue.StringVal = sub.AllowedSourceDomainComputers.c_str();
if (!EcSetSubscriptionProperty(hSubscription,
EcSubscriptionAllowedSourceDomainComputers,
0,
&vPropertyValue))
{
dwRetVal = GetLastError();
goto Cleanup;
}
//----------------------------------------------
// Step 3: Save the subscription.
// Save the subscription with the associated properties
// This will create the subscription and store it in the
// subscription repository
if( !EcSaveSubscription(hSubscription, NULL) )
{
dwRetVal = GetLastError();
goto Cleanup;
}
// Step 4: Close the subscription.
Cleanup:
if(hSubscription)
EcClose(hSubscription);
if (dwRetVal != ERROR_SUCCESS)
{
FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwRetVal,
0,
(LPWSTR) &lpwszBuffer,
0,
NULL);
if (!lpwszBuffer)
{
wprintf(L"Failed to FormatMessage. Operation Error Code: %u." \
L"Error Code from FormatMessage: %u\n", dwRetVal, GetLastError());
return;
}
wprintf(L"\nFailed to Perform Operation.\nError Code: %u\n" \
L" Error Message: %s\n", dwRetVal, lpwszBuffer);
LocalFree(lpwszBuffer);
}
}
DWORD GetProperty(EC_HANDLE hSubscription,
EC_SUBSCRIPTION_PROPERTY_ID propID,
DWORD flags,
std::vector<BYTE>& buffer,
PEC_VARIANT& vProperty)
{
DWORD dwBufferSize, dwRetVal = ERROR_SUCCESS;
buffer.resize(sizeof(EC_VARIANT));
if (!hSubscription)
return ERROR_INVALID_PARAMETER;
// Get the value for the specified property.
if (!EcGetSubscriptionProperty(hSubscription,
propID,
flags,
(DWORD) buffer.size(),
(PEC_VARIANT)&buffer[0],
&dwBufferSize) )
{
dwRetVal = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == dwRetVal)
{
dwRetVal = ERROR_SUCCESS;
buffer.resize(dwBufferSize);
if (!EcGetSubscriptionProperty(hSubscription,
propID,
flags,
(DWORD) buffer.size(),
(PEC_VARIANT)&buffer[0],
&dwBufferSize))
{
dwRetVal = GetLastError();
}
}
}
if (dwRetVal == ERROR_SUCCESS)
{
vProperty = (PEC_VARIANT) &buffer[0];
}
else
{
vProperty = NULL;
}
return dwRetVal;
}
验证订阅是否正常工作
在事件收集器计算机上,完成以下过程:
从提升的权限命令提示符运行以下命令,以获取订阅的运行时状态:
wecutil gr <subscriptionID>
验证事件源是否已连接。 在为要连接的事件源创建订阅后,可能需要等待策略中指定的刷新间隔结束。
运行以下命令以获取订阅信息:
wecutil gs <subscriptionID>
从订阅信息获取 DeliveryMaxItems 值。
在事件源计算机上,从事件订阅中引发与查询匹配的事件。 要转发事件,必须触发事件的 DeliveryMaxItems 数。
在事件收集器计算机上,验证事件是否已转发到 ForwardedEvents 日志或订阅中指定的日志。
相关主题