💡 Windows Event Forwarding – How do I use it?
Windows Event Forwarding is a bit of pain to setup and get it run correctly. This module has some functions built-in that are supposed to help you set it up correctly from A to Y. The last Z step you may need to do yourself. And that are permissions. Keep in mind that you can either choose totally separate machine for this task (but as secure as your DC) or even use your DC if you have small enough domain. I'm encouraging you to start using Forwarding for a simple reason.. scanning 2,5,10 domain controllers for events that often store 99% more information is both time consuming and hard to maintain. By enabling Windows Event Forwarding you get few new features and old features work in seconds/minutes instead of minutes/hours.
To get it up and running you need 4 things:
- You need to create Subscription for LOGS on your Windows Log Collector so that it can PULL data from Domain Controllers
- You need a script (RunMe-TriggerOnEvents.ps1) that will be executed anytime new event log is added on Windows Log Collector
- You need to attach that script to Task Scheduler so that when new event is pulled from Domain Controllers it's fed to the script. This can be setup by hand or by using RunMe-CreateTasks.ps1 that is part of this package.
- You need to have permissions to set this up (which is a bit out of scope of this module for now)
Keep in mind that this script sets up things on defaults. It doesn't ask you for credentials, it doesn't set up any permissions. This means that if new Task Schedule is created it works under SYSTEM account. Same goes for Subscriptions. If it's setup it uses Machine Account. You can and should change that to match your domain.
Import-Module PSWinReporting -Force
Import-Module PSSharedGoods -Force
$ReportDefinitions = @{
ReportsAD = @{
Servers = @{
Automatic = $true
OnlyPDC = $false
DC = ''
}
EventBased = @{
UserChanges = @{
Enabled = $true
Events = 4720, 4738
LogName = 'Security'
}
UserStatus = @{
Enabled = $true
Events = 4722, 4725, 4767, 4723, 4724, 4726
LogName = 'Security'
}
ComputerCreatedChanged = @{
Enabled = $true
Events = 4741, 4742 # created, changed
LogName = 'Security'
IgnoreWords = ''
}
ComputerDeleted = @{
Enabled = $true
Events = 4743 # deleted
LogName = 'Security'
IgnoreWords = ''
}
UserLockouts = @{
Enabled = $true
Events = 4740
LogName = 'Security'
}
GroupMembershipChanges = @{
Enabled = $true
Events = 4728, 4729, 4732, 4733, 4756, 4757, 4761, 4762
LogName = 'Security'
}
GroupCreateDelete = @{
Enabled = $true
Events = 4727, 4730, 4731, 4734, 4759, 4760, 4754, 4758
LogName = 'Security'
}
GroupPolicyChanges = @{
Enabled = $true
Events = 5136, 5137, 5141
LogName = 'Security'
}
LogsClearedSecurity = @{
Enabled = $true
Events = 1102, 1105
LogName = 'Security'
}
LogsClearedOther = @{
Enabled = $true
Events = 104
LogName = 'System'
}
}
}
}
Start-SubscriptionService
$Providers = New-SubscriptionTemplates -ReportDefinitions $ReportDefinitions -Verbose
Set-SubscriptionTemplates -ListTemplates $Providers -DeleteOwn
Script above sets up Event Log Subscriptions. When it's run it should create 1 or more Subscriptions that will cover your whole domain and what you've set up in configuration. Depending on what you've chosen in config it can be 1,2 or 3 new subscriptions. When you rerun the script it will create all necessary providers and will use built-in template that comes with PowerShell Module. It's encouraged to use this module directly from PowerShellGallery. Keep in mind that script when rerun will delete it's own providers and recreate them on per need basis. This means you can enable some things now, and simply add things at later date.
And when you check Event Viewer you should have something similar to the one below
When you right click on each of subscriptions you can check Run time status. It's very important step and you should spend time on getting this right. It's a matter of permissions or WinRM to get this run properly. Don't be discouraged. It will work 😉
If everything went OK, you should start seeing events you chosen (and couple of default ones) in your Forwarded Events log
Next step is to copy script below and putting it in place that will be used for Task Scheduler to start it.
# Collects all named paramters (all others end up in $Args)
param(
$eventid = 1105,
$eventRecordID = 1854610, # 425358 ,
$eventChannel,
$eventSeverity
)
<#
Update-Module PSTeams
Update-Module PSEventViewer
Update-Module PSWinReporting
Update-Module PSWriteColor
Update-Module PSWriteExcel
Update-Module PSSlack
Update-Module DBATools
#>
Import-Module PSTeams
Import-Module PSEventViewer
Import-Module PSWinReporting -Force
Import-Module PSWriteColor
Import-Module PSSlack
Import-Module DBATools
Import-Module PSSharedGoods #-Force
$ReportOptions = @{
JustTestPrerequisite = $false # runs testing without actually running script
AsExcel = $true # attaches Excel to email with all events, required PSWriteExcel module
AsCSV = $false # attaches CSV to email with all events,
AsHTML = $true # puts exported data into email directly with all events
SendMail = $false
OpenAsFile = $true # requires AsHTML set to $true
KeepReports = $true # keeps files after reports are sent (only if AssExcel/AsCSV are in use)
KeepReportsPath = 'C:\Support\Reports\ExportedEvents' # if empty, temp path is used
FilePattern = 'Evotec-ADMonitoredEvents-<currentdate>.<extension>'
FilePatternDateFormat = 'yyyy-MM-dd-HH_mm_ss'
DisplayConsole = @{
ShowTime = $false
LogFile = 'C:\testing.log'
TimeFormat = 'yyyy-MM-dd HH:mm:ss'
}
Debug = @{
DisplayTemplateHTML = $false
Verbose = $false
}
Notifications = @{
MicrosoftTeams = @{
Use = $false
TeamsID = ''
}
Slack = @{
Use = $false
Channel = '#general'
Uri = ""
}
MSSQL = @{
Use = $false
SqlServer = 'EVO1'
SqlDatabase = 'SSAE18'
SqlTable = 'dbo.[Events]'
# Left side is data in PSWinReporting. Right Side is ColumnName in SQL
# Changing makes sense only for right side...
SqlTableCreate = $true
SqlTableAlterIfNeeded = $true
SqlTableMapping = [ordered] @{
'Event ID' = 'EventID,[int]'
'Who' = 'EventWho'
'When' = 'EventWhen,[datetime]'
'Record ID' = 'EventRecordID,[bigint]'
'Domain Controller' = 'DomainController'
'Action' = 'Action'
'Group Name' = 'GroupName'
'User Affected' = 'UserAffected'
'Member Name' = 'MemberName'
'Computer Lockout On' = 'ComputerLockoutOn'
'Reported By' = 'ReportedBy'
'SamAccountName' = 'SamAccountName'
'Display Name' = 'DisplayName'
'UserPrincipalName' = 'UserPrincipalName'
'Home Directory' = 'HomeDirectory'
'Home Path' = 'HomePath'
'Script Path' = 'ScriptPath'
'Profile Path' = 'ProfilePath'
'User Workstation' = 'UserWorkstation'
'Password Last Set' = 'PasswordLastSet,[datetime]'
'Account Expires' = 'AccountExpires,[datetime]'
'Primary Group Id' = 'PrimaryGroupId'
'Allowed To Delegate To' = 'AllowedToDelegateTo'
'Old Uac Value' = 'OldUacValue'
'New Uac Value' = 'NewUacValue'
'User Account Control' = 'UserAccountControl'
'User Parameters' = 'UserParameters'
'Sid History' = 'SidHistory'
'Logon Hours' = 'LogonHours'
'OperationType' = 'OperationType'
'Message' = 'Message'
'Backup Path' = 'BackupPath'
'Log Type' = 'LogType'
'AddedWhen' = 'EventAdded,[datetime],null' # ColumnsToTrack when it was added to database and by who / not part of event
'AddedWho' = 'EventAddedWho' # ColumnsToTrack when it was added to database and by who / not part of event
}
}
}
Backup = @{
Use = $true
DestinationPath = 'C:\MyEvents\'
}
}
$ReportDefinitions = @{
TimeToGenerate = $false
TeamsID = ''
ReportsAD = @{
Servers = @{
ForwardServer = $env:COMPUTERNAME
ForwardEventLog = 'ForwardedEvents'
}
EventBased = @{
UserChanges = @{
Enabled = $true
Events = 4720, 4738
LogName = 'Security'
IgnoreWords = ''
}
UserStatus = @{
Enabled = $true
Events = 4722, 4725, 4767, 4723, 4724, 4726
LogName = 'Security'
IgnoreWords = @{
'Domain Controller' = ''
'Action' = ''
'User Affected' = 'Win-*', '*AD1$*'
'Who' = ''
'When' = ''
'Event ID' = ''
'Record ID' = ''
}
}
UserLockouts = @{
Enabled = $true
Events = 4740
LogName = 'Security'
IgnoreWords = ''
}
UserLogon = @{
Enabled = $false
Events = 4624
LogName = 'Security'
IgnoreWords = ''
}
ComputerCreatedChanged = @{
Enabled = $true
Events = 4741, 4742 # created, changed
LogName = 'Security'
IgnoreWords = ''
}
ComputerDeleted = @{
Enabled = $true
Events = 4743 # deleted
LogName = 'Security'
IgnoreWords = ''
}
UserLogonKerberos = @{
Enabled = $false
Events = 4768
LogName = 'Security'
IgnoreWords = ''
}
GroupMembershipChanges = @{
Enabled = $true
Events = 4728, 4729, 4732, 4733, 4756, 4757, 4761, 4762
LogName = 'Security'
IgnoreWords = @{
'Who' = '*ANONYMOUS*'
}
}
GroupCreateDelete = @{
Enabled = $true
Events = 4727, 4730, 4731, 4734, 4759, 4760, 4754, 4758
LogName = 'Security'
IgnoreWords = @{
'Who' = '*ANONYMOUS*'
}
}
GroupPolicyChanges = @{
Enabled = $false
Events = 5136, 5137, 5141
LogName = 'Security'
IgnoreWords = ''
}
LogsClearedSecurity = @{
Enabled = $true
Events = 1102, 1105
LogName = 'Security'
IgnoreWords = ''
}
LogsClearedOther = @{
Enabled = $true
Events = 104
LogName = 'System'
IgnoreWords = ''
}
EventsReboots = @{
Enabled = $false
Events = 1001, 1018, 1, 12, 13, 42, 41, 109, 1, 6005, 6006, 6008, 6013
LogName = 'System'
IgnoreWords = ''
}
}
}
}
Start-Notifications -ReportDefinitions $ReportDefinitions -ReportOptions $ReportOptions -EventID $EventID -EventRecordID $EventRecordID -EventChannel $EventChannel #-Verbose
Keep in mind this script when started will do nothing by itself. On top of it there are 4 parameters with 2 filled in (EventID and EventRecordID). If you want to use this by hand for verification you can find and Event in your Forwarded Events log and use that as a testing exercise to see if you're getting any data to MS Teams, Slack or SQL.
Finally there is one last script that has to be run (or you can set it up manually). Getting the script above to be executed by Task Scheduler when event happens. This script below will create new Task and attach it to ForwardedEvents logs.
Import-Module PSWinReporting -Force
Import-Module PSSharedGoods -Force
$TaskName = 'ForwardedEvents'
$TaskPath = '\Event Viewer Tasks\'
$Author = 'EVOTEC'
$URI = '\Event Viewer Tasks\ForwardedEvents'
$Command = 'powershell.exe'
$Argument = @('-windowstyle hidden', 'C:\Support\GitHub\PSWinReporting\Examples\RunMe-TriggerOnEvents.ps1', '-EventID $(eventID) -eventRecordID $(eventRecordID) -eventChannel $(eventChannel) -eventSeverity $(eventSeverity)')
Remove-TaskScheduledForwarder -TaskPath $TaskPath -TaskName $TaskName
Add-TaskScheduledForwarder -TaskPath $TaskPath -TaskName $TaskName -Author $Author -URI $Uri -Command $Command -Argument $Argument
Output should be something similar to below. Keep in mind that we again use Template that comes in with this PowerShell Module. You should verify created Task whether it has proper permissions and proper setup.
After all those 3 scripts are setup you really need to test this out. Make sure that if you run the task manually that you get notifications you expect (that's why the “default” test data comes useful in the defined parameters). It may take a while before you get this right. It's very important step to get other things running properly.
Please notice this article contains parts of information (still useful) and may not reflect all functionalities of this module. For download, source code and so on you should refer to the dedicated PSWinReporting module page. After reading this one… of course! It contains useful information, examples and know-how.