EvotecIT / PSWinReporting

This PowerShell Module has multiple functionalities, but one of the signature features of this module is the ability to parse Security logs on Domain Controllers providing easy to use access to AD Events.
MIT License
701 stars 69 forks source link

Not sending to Teams #75

Closed jay7981 closed 1 year ago

jay7981 commented 1 year ago

I cannot seem to get this to send data to teams even though i have Teams set to true and entered a valid webhook url ... I have event forwarding setup and working, below is the TriggerOnEvents script that i am attempting to use.

param(
    $eventid = 5136,
    $eventRecordID = 7488468, # 425358 ,
    $eventChannel,
    $eventSeverity
)
$ReportOptions = @{
    JustTestPrerequisite  = $false # runs testing without actually running script
    AsExcel               = $false # attaches Excel to email with all events, required ImportExcel 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           = 'ADMonitoredEvents-<currentdate>.<extension>'
    FilePatternDateFormat = 'yyyy-MM-dd-HH_mm_ss'
    DisplayConsole        = @{
        ShowTime   = $true
        LogFile    = ''
        TimeFormat = 'yyyy-MM-dd HH:mm:ss'
    }
    Debug                 = @{
        DisplayTemplateHTML = $true
        Verbose             = $true
    }
    Notifications         = @{
        MicrosoftTeams = @{
            Use     = $true
            TeamsID = 'Webhook URL'
        }
        Slack          = @{
            Use     = $false
            Channel = '#general'
            Uri     = ""
        }
        MSSQL          = @{
            Use                   = $true
            SqlServer             = 'Server1'
            SqlDatabase           = 'DB1'
            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
            SqlCheckBeforeInsert  = 'EventRecordID', 'DomainController' # Based on column name

            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
                'Gathered From'          = 'GatheredFrom'
                'Gathered LogName'       = 'GatheredLogName'
            }
        }
    }
    Backup                = @{
        Use             = $false
        DestinationPath = 'E:\EventLogs'
    }
}
$ReportDefinitions = @{
    TimeToGenerate = $false
    ReportsAD      = @{
        Servers    = @{
            UseForwarders   = $true # if $true skips Automatic/OnlyPDC/DC for reading logs. However it uses Automatic to deliver size of logs so keep Automatic to $true
            ForwardServer   = $ENV:COMPUTERNAME
            ForwardEventLog = 'ForwardedEvents'
            UseDirectScan   = $true
            Automatic       = $true # will use all DCs for a forest
            OnlyPDC         = $false # will use PDC of current domain returned by Get-ADDomain
            DC              = ''
        }
        EventBased = @{
            UserChanges            = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 4720, 4738
                LogName          = 'Security'
                IgnoreWords      = ''
            }
            UserStatus             = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 4722, 4725, 4767, 4723, 4724, 4726
                LogName          = 'Security'
                IgnoreWords      = @{
                    'Domain Controller' = ''
                    'Action'            = ''
                    'User Affected'     = 'Win-*', '*AD1$*'
                    'Who'               = ''
                    'When'              = ''
                    'Event ID'          = ''
                    'Record ID'         = ''
                }
                ExportToSql      = @{
                    # per Event Category / Global SQL is above
                    Use                   = $true
                    SqlServer             = 'Server1'
                    SqlDatabase           = 'DB1'
                    SqlTable              = 'dbo.[EventsUserStatus]'
                    # Left side is data in PSWinReporting. Right Side is ColumnName in SQL
                    # Changing makes sense only for right side...
                    SqlTableCreate        = $true
                    SqlTableAlterIfNeeded = $false # if table mapping is defined doesn't do anything
                    SqlCheckBeforeInsert  = 'EventRecordID', 'DomainController' # Based on column name
                    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
                        #   'Gathered From'          = 'GatheredFrom'
                        #   'Gathered LogName'       = 'GatheredLogName'
                    }
                }
            }
            UserLockouts           = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 4740
                LogName          = 'Security'
                IgnoreWords      = ''
            }
            UserLogon              = @{
                Enabled          = $false
                EnabledSqlGlobal = $true
                Events           = 4624
                LogName          = 'Security'
                IgnoreWords      = ''
            }
            UserLogonKerberos      = @{
                Enabled          = $false
                EnabledSqlGlobal = $true
                Events           = 4768
                LogName          = 'Security'
                IgnoreWords      = ''
            }
            GroupMembershipChanges = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 4728, 4729, 4732, 4733, 4756, 4757, 4761, 4762
                LogName          = 'Security'
                IgnoreWords      = @{
                    'Who' = '*ANONYMOUS*'
                }
                ExportToSql      = @{
                    # per Event Category / Global SQL is above
                    Use                   = $true
                    SqlServer             = 'Sever1'
                    SqlDatabase           = 'DB1'
                    SqlTable              = 'dbo.[EventsGroupMembershipChanges]'
                    # Left side is data in PSWinReporting. Right Side is ColumnName in SQL
                    # Changing makes sense only for right side...
                    SqlTableCreate        = $true
                    SqlTableAlterIfNeeded = $false # if table mapping is defined doesn't do anything
                    SqlCheckBeforeInsert  = 'EventRecordID', 'DomainController' # Based on column name
                }
            }
            GroupCreateDelete      = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 4727, 4730, 4731, 4734, 4759, 4760, 4754, 4758
                LogName          = 'Security'
                IgnoreWords      = @{
                    'Who' = '*ANONYMOUS*'
                }
            }
            GroupPolicyChanges     = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 5136, 5137, 5141
                LogName          = 'Security'
                IgnoreWords      = ''
            }
            LogsClearedSecurity    = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 1102
                LogName          = 'Security'
                IgnoreWords      = ''
            }
            LogsClearedOther       = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 104
                LogName          = 'System'
                IgnoreWords      = ''
            }
            EventsReboots          = @{
                Enabled          = $false
                EnabledSqlGlobal = $true
                Events           = 1001, 1018, 1, 12, 13, 42, 41, 109, 1, 6005, 6006, 6008, 6013
                LogName          = 'System'
                IgnoreWords      = ''
            }
            ComputerCreatedChanged = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 4741, 4742 # created, changed
                LogName          = 'Security'
                IgnoreWords      = ''
            }
            ComputerDeleted        = @{
                Enabled          = $true
                EnabledSqlGlobal = $true
                Events           = 4743 # deleted
                LogName          = 'Security'
                IgnoreWords      = ''
            }
        }
    }
}
Import-Module PSWinReporting -Force
Import-Module DBATools
Import-Module PSSharedGoods
#Import-Module PSSlack
Import-Module PSTeams
$startNotificationsSplat = @{
    EventChannel      = $EventChannel
    EventID           = $EventID
    ReportDefinitions = $ReportDefinitions
    ReportOptions     = $ReportOptions
    EventRecordID     = $EventRecordID
}
Start-Notifications @startNotificationsSplat
PrzemyslawKlys commented 1 year ago

What about any errors or things like that? Any warnings, any output?

jay7981 commented 1 year ago

Here is the output from the RunMe-TriggerOnEvents.ps1

[2022-10-13 14:13:35] [i] Executed Trigger for ID: 5136 and RecordID: 7488468
[2022-10-13 14:13:35] [i] Using Microsoft Teams: True
[2022-10-13 14:13:35] [i] TeamsID: WebhookURL...
[2022-10-13 14:13:35] [i] Using Slack: False
[2022-10-13 14:13:35] [i] Using MSSQL: True
VERBOSE: Get-Events - Preparing data to scan computer Server1
VERBOSE: Get-Events - Filter parameters provided LogName = ForwardedEvents
VERBOSE: Get-Events - Filter parameters provided RecordID = 7488468
VERBOSE: Get-Events - Events to process in Total (unique): 1
VERBOSE: Get-Events - Events to process in Total ID: 5136
VERBOSE: Get-Events - Running query with parallel enabled...
VERBOSE: Get-Events -------------START---------------------
VERBOSE: Get-Events - Inside Server1 for Events ID: 5136
VERBOSE: Get-Events - Inside Server1 for Events LogName: ForwardedEvents
VERBOSE: Get-Events - Inside Server1  for Events RecordID: 7488468
VERBOSE: Get-Events - Inside Server1 for Events Oldest: False
VERBOSE: Get-Events - Inside Server1 - Custom FilterXML: 
                    <QueryList>
                        <Query Id="0" Path="ForwardedEvents">
                            <Select Path="ForwardedEvents">
                                    (*[System[EventID=5136]]) and (*[System[EventRecordID=7488468]])
                            </Select>
                        </Query>
                    </QueryList>
VERBOSE: Get-Events - Inside Server1 No events found.
VERBOSE: Get-Events - Inside Server1 Time to generate 0 hours, 0 minutes, 0 seconds, 245 milliseconds
VERBOSE: Get-Events --------------END----------------------
VERBOSE: Get-Events - Overall errors: 0
VERBOSE: Get-Events - Overall events processed in total for the report: 0
VERBOSE: Get-Events - Overall time to generate 0 hours, 0 minutes, 0 seconds, 615 milliseconds
VERBOSE: Get-Events - Overall events processing end
[2022-10-13 14:13:36] [i] Running User Changes Report.
[2022-10-13 14:13:36] [i] Ending User Changes Report.
[2022-10-13 14:13:36] [i] Running User Statues Report.
[2022-10-13 14:13:36] [i] Ending User Statues Report.
[2022-10-13 14:13:36] [i] Running User Lockouts Report.
[2022-10-13 14:13:36] [i] Ending User Lockouts Report.
[2022-10-13 14:13:36] [i] Running Computer Created / Changed Report.
[2022-10-13 14:13:36] [i] Ending Computer Created / Changed Report.
[2022-10-13 14:13:36] [i] Running Computer Deleted Report.
[2022-10-13 14:13:36] [i] Ending Computer Deleted Report.
[2022-10-13 14:13:36] [i] Running Group Membership Changes Report
[2022-10-13 14:13:36] [i] Ending Group Membership Changes Report.
[2022-10-13 14:13:36] [i] Running Group Create/Delete Report.
[2022-10-13 14:13:36] [i] Ending Group Create/Delete Report.
[2022-10-13 14:13:36] [i] Running Group Policy Changes Report.
[2022-10-13 14:13:36] [i] Ending Group Policy Changes Report.
[2022-10-13 14:13:36] [i] Running Who Cleared Logs Report.
[2022-10-13 14:13:36] [i] Ending Who Cleared Logs Report.
[2022-10-13 14:13:36] [i] Running Who Cleared Logs Report.
[2022-10-13 14:13:36] [i] Ending Who Cleared Logs Report.

No errors or warnings at all.

jay7981 commented 1 year ago

As you can see i have the Event Forwarding working https://prnt.sc/-T3zQ_QGOmCT https://prnt.sc/XYG_0qEYwvXa https://prnt.sc/Vd2_MoiYrg5h

PrzemyslawKlys commented 1 year ago

Can you try on something else than a GPO. GPO changes is pretty special, so maybe the conditions are not met when parsing GPO event. And I assume the WebhookURL is placeholder and normally there's like https://... right?

jay7981 commented 1 year ago

do you mean try setting it up on a server that is not a domain controller? GPO = Group Policy Object ... and i am not using GPO for this in any way .... and yes the webhook is just a placeholder as to not compromise my system/company. Yes its a web url like https://... it was copied and pasted from teams connectors page https://prnt.sc/CBvZqiD3TH-r

PrzemyslawKlys commented 1 year ago

no, i mean you are testing this with event ID 5136 which is a group policy object change. Try different ID, something with add computer, delete computer etc

Hrmms, looking at the logs...

                <QueryList>
                    <Query Id="0" Path="ForwardedEvents">
                        <Select Path="ForwardedEvents">
                                (*[System[EventID=5136]]) and (*[System[EventRecordID=7488468]])
                        </Select>
                    </Query>
                </QueryList>

Matches exactly this:

param(
    $eventid = 5136,
    $eventRecordID = 7488468, # 425358 ,
    $eventChannel,
    $eventSeverity
)

So it means that you are testing this manually with "wrong id". FInd an even in your forwarded logs that exists, enter it into this params, once you execute this manually - it should work. If it works, then you need to set it up properly.

jay7981 commented 1 year ago

sorry for the late response, its been crazy at work so i have been real busy. Can i just omit the param section all together and have it report ALL AD events?

jay7981 commented 1 year ago

Over all my goal is to have it email a daily report for the AD changes that happened the day before and have teams post all changes live as they are made. What is the best way/script to accomplish this?

PrzemyslawKlys commented 1 year ago

The way it works is that param section is critical, because you are not supposed to trigger it manually.

The process is described here: https://evotec.xyz/pswinreporting-forwarders-microsoft-teams-slack-microsoft-sql-and-more/

In short:

  1. Setup forwarding on all your domain controllers into a single machine so all relevant security logs ar sent to this particular ForwardedEvents log
  2. Go to that forwarded events log and see if new events from all DCs show up in it
  3. Pick one of the events - note the Event Record ID and Event ID and enter those into param block into the script
  4. Run the script manually in VSCode or ISE.
  5. You should get notification - if it works, your script is ready for production.

Now what you need to do is setup Task scheduler that will be assigned to that ForwardedEvents log. What will happen is that for every single event that shows up in that log - it will trigger a script with relevant event id and eventrecordid

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

In other words your DCS will be sending all events to a central place, and for every event they send the script will trigger with specific id, specific event. The param values will be overwritten and the block is required.