EventMonitor/LogonIndicators.psm1

<#PSScriptInfo
.AUTHOR Microsoft
.COMPANYNAME Microsoft Corporation
.COPYRIGHT (c) Microsoft Corporation
#>


$EventLogType = @{
    SecurityLogs = "Security";
    SystemLogs = "System";
    ApplicationLogs = "Application";
    SetupLogs = "Setup";
    OpenSSHOperationalLogs = "OpenSSH/Operational";
};

<#
.SYNOPSIS
    ##############################################################################################################################
    Get the user Logoff related events and return the latest logoff event with its details.
    ##############################################################################################################################
.DESCRIPTION
    Gets the details of the latest windows logoff related events and returns the latest event among those events. The list of events
    considered to be logoff related are
    1) OpenSSHApplication: OpenSSH/Operational This OpenSSH application event is generated when SSH connected
    2) 4648: This event is generated when a process attempts an account logon by explicitly specifying that account’s credentials..
    3) 4624: This event generates when a logon session is created (on destination machine). It generates on the computer that was accessed, where the session was created.
    4) 5140: This event generates every time network share object was accessed.
    5) 4801: This event is generated when workstation was unlocked.
    6) 4634: This is not a logoff event but session end event, disabled as it gets fired for both logon/logoff
#>

function Get-UserInteractionEvents {
    param(
        [Parameter(Mandatory = $true)]
        [string] $logAnalyticsConString,
        [Parameter(Mandatory = $true)]
        [string] $sessionId,
        [Parameter(Mandatory = $true)]
        [DateTime] $TimeBefore,
        [Parameter(Mandatory = $true)]
        [string] $User
    )
    # OpenSSH/Operational log
    Get-OpenSSHApplication_Event_Connect -sessionId $sessionId -User $User -TimeBefore $TimeBefore -logAnalyticsConString $logAnalyticsConString;
    # 4624
    Get-Event_4624 -sessionId $sessionId -User $User -TimeBefore $TimeBefore -logAnalyticsConString $logAnalyticsConString;
    # 4801
    Get-Event_4801_MachineUnlocked -sessionId $sessionId -User $User -TimeBefore $TimeBefore -logAnalyticsConString $logAnalyticsConString;
    # 5140
    Get-Event_5140_NetworkShareAccess -sessionId $sessionId -User $User -TimeBefore $TimeBefore -logAnalyticsConString $logAnalyticsConString;
    # 4648
    Get-Event_4648 -sessionId $sessionId -User $User -TimeBefore $TimeBefore -logAnalyticsConString $logAnalyticsConString;
}

<#
.SYNOPSIS
    ##############################################################################################################################
    # OpenSSH/Operational This OpenSSH application event is generated when SSH connection is requested.
    ##############################################################################################################################
#>

function Get-OpenSSHApplication_Event_Connect {
    param(
        [Parameter(Mandatory = $true)]
        [string] $logAnalyticsConString,
        [Parameter(Mandatory = $true)]
        [string] $sessionId,
        [Parameter(Mandatory = $true)]
        [string] $User,
        [Parameter(Mandatory = $true)]
        [DateTime] $TimeBefore
    )
    Import-Module -Name "$PSScriptRoot\EMCommon.psm1"
    Import-Module -Name "$PSScriptRoot\Telemetry\AITelemetry.psm1"
    $LogFilePath = "$PSScriptRoot\Telemetry\Logs.txt";

    try {
        $events = Get-WinEvent -FilterHashtable @{logname=$EventLogType.OpenSSHOperationalLogs;} -ErrorAction Stop `
            | Where-Object { (($_.properties[1].value -like 'Accepted publickey*') -and ($_.TimeCreated -ge $TimeBefore ) )}
        if ($null -ne $events -and $events.count -gt 0) {
            $events | ForEach-Object {
                $sendEvent = $_
                $message = $sendEvent.Message;
                $userName = $message.split(" ")[4].split("@")[0];
                $UserSID = $sendEvent.UserId.Value
                if ($userName -ne $user) { continue }

                $EvProps = New-Object 'system.collections.generic.dictionary[string, string]'
                $EvProps.Add("SessionId", $sessionId)
                $EvProps.Add("EventType", "Connect")
                # Add metadata info about event to be useful
                $EvProps.Add("UserName", "$user")
                $EvProps.Add("Process", "$($message.split(" ")[0])")
                $EvProps.Add("IPAddress", "$($message.split(" ")[6])")
                $EvProps.Add("IPPort", "$($message.split(" ")[8])")
                $EvProps.Add("UserSID", "$UserSID")

                Send-LogAnalyticsConnectEvents `
                    -eventName "OpenSSH/Operational Connect Event" `
                    -Properties $EvProps `
                    -sendEvent $sendEvent `
                    -logAnalyticsConString $logAnalyticsConString;
            }
        }
    }
    catch {
        if ($_ -notlike "*No events were found*") { 
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: Exception Message: `n$_.Exception.Message"
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: ScriptStackTrace: `n$_.ScriptStackTrace"
            $LASTEXITCODE = 1
            $ErrorProps = New-Object 'system.collections.generic.dictionary[string, string]'
            $ErrorProps.Add("SessionId", "$sessionId")
            $ErrorProps.Add("User", "$User")
            $ErrorProps.Add("Query events since", "$TimeBefore")
            $ErrorProps.Add("Function", "Get-OpenSSHApplication_Event_Connect")
            TrackException -ErrorRecord $_ -Properties $ErrorProps -logAnalyticsConString $logAnalyticsConString;;
        }
    }
    finally { }
}


<#
.SYNOPSIS
    ##############################################################################################################################
    # 4648 This event is generated when a process attempts an account logon by explicitly specifying that account’s credentials..
    ##############################################################################################################################
#>

function Get-Event_4648 {
    param(
        [Parameter(Mandatory = $true)]
        [string] $logAnalyticsConString,
        [Parameter(Mandatory = $true)]
        [string] $sessionId,
        [Parameter(Mandatory = $true)]
        [string] $User,
        [Parameter(Mandatory = $true)]
        [DateTime] $TimeBefore
    )
    Import-Module -Name "$PSScriptRoot\EMCommon.psm1"
    Import-Module -Name "$PSScriptRoot\Telemetry\AITelemetry.psm1"
    $LogFilePath = "$PSScriptRoot\Telemetry\Logs.txt";

    try {
        $allEvents = Get-WinEvent -FilterHashtable @{logname=$EventLogType.SecurityLogs; id=4648} -ErrorAction Stop `
            | Where-Object { (($_.properties[5].Value -eq $User -or $_.properties[5].Value -like 'ssh_*') -and ($_.TimeCreated -ge $TimeBefore))}

        $events = $allEvents | Where-Object { (($_.properties[11].value -like '*sshd.exe') -or ($_.properties[11].value -like '*svchost.exe'))}
        if ($null -ne $events -and $events.count -gt 0) {
            $events | ForEach-Object { 
                $sendEvent = $_
                $EvProps = New-Object 'system.collections.generic.dictionary[string, string]'
                $EvProps.Add("SessionId", $sessionId)
                $EvProps.Add("EventType", "Connect")
                # Add metadata info about event to be useful
                $EvProps.Add("AccountDomain", "$($sendEvent.properties[2].Value)")
                $EvProps.Add("UserName", "$User")
                # Defines SSH connection or RDP based on process
                # SSH connection if its -like *sshd.exe
                # RDP connection if its -like *svchost.exe
                $EvProps.Add("Process", "$($sendEvent.properties[11].Value)")

                Send-LogAnalyticsConnectEvents `
                    -eventName "$($sendEvent.Id) Connect Event" `
                    -Properties $EvProps `
                    -sendEvent $sendEvent `
                    -logAnalyticsConString $logAnalyticsConString;
            }
        }
    }
    catch {
        if ($_ -notlike "*No events were found*") { 
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: Exception Message: `n$_.Exception.Message"
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: ScriptStackTrace: `n$_.ScriptStackTrace"
            $LASTEXITCODE = 1
            $ErrorProps = New-Object 'system.collections.generic.dictionary[string, string]'
            $ErrorProps.Add("SessionId", "$sessionId")
            $ErrorProps.Add("User", "$User")
            $ErrorProps.Add("Query events since", "$TimeBefore")
            $ErrorProps.Add("Function", "Get-Event_4648")
            TrackException -ErrorRecord $_ -Properties $ErrorProps -logAnalyticsConString $logAnalyticsConString;
        }
    }
    finally { }
}


<#
.SYNOPSIS
    ##############################################################################################################################
    # 4624 This event generates when a logon session is created (on destination machine). It generates on the computer that was accessed, where the session was created.
    ##############################################################################################################################
#>

function Get-Event_4624 {
    param(
        [Parameter(Mandatory = $true)]
        [string] $logAnalyticsConString,
        [Parameter(Mandatory = $true)]
        [string] $sessionId,
        [Parameter(Mandatory = $true)]
        [string] $User,
        [Parameter(Mandatory = $true)]
        [DateTime] $TimeBefore
    )
    Import-Module -Name "$PSScriptRoot\EMCommon.psm1"
    Import-Module -Name "$PSScriptRoot\Telemetry\AITelemetry.psm1"
    $LogFilePath = "$PSScriptRoot\Telemetry\Logs.txt";

    try {
        $allEvents = Get-WinEvent -FilterHashtable @{logname=$EventLogType.SecurityLogs; id=4624} -ErrorAction Stop `
            | Where-Object { ( ($_.properties[5].Value -eq $User -or $_.properties[5].Value -like 'ssh_*') -and ($_.TimeCreated -ge $TimeBefore))}

        $events = $allEvents | Where-Object { (($_.properties[17].value -like  '*sshd.exe') -or ($_.properties[17].Value -like  '*svchost.exe'))}
        if ($null -ne $events -and $events.count -gt 0) {
            $events | ForEach-Object { 
                $sendEvent = $_
                $EvProps = New-Object 'system.collections.generic.dictionary[string, string]'
                $EvProps.Add("SessionId", $sessionId)
                $EvProps.Add("EventType", "Connect")
                # Add metadata info about event to be useful
                $EvProps.Add("AccountDomain", "$($sendEvent.properties[2].Value)")
                $EvProps.Add("LogonSID", "$($sendEvent.properties[4].Value)")
                $EvProps.Add("UserName", "$($sendEvent.properties[5].Value)")
                $EvProps.Add("LogonType", "$($sendEvent.properties[8].Value)")
                $EvProps.Add("LogonProcess", "$($sendEvent.properties[9].Value)")
                # Defines SSH connection or RDP based on process
                # SSH connection if its -like *sshd.exe
                # RDP connection if its -like *svchost.exe
                $EvProps.Add("Process", "$($sendEvent.properties[17].Value)")

                Send-LogAnalyticsConnectEvents `
                    -eventName "$($sendEvent.Id) Connect Event" `
                    -Properties $EvProps `
                    -sendEvent $sendEvent `
                    -logAnalyticsConString $logAnalyticsConString;
            }
        }
    }
    catch {
        if ($_ -notlike "*No events were found*") { 
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: Exception Message: `n$_.Exception.Message"
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: ScriptStackTrace: `n$_.ScriptStackTrace"
            $LASTEXITCODE = 1
            $ErrorProps = New-Object 'system.collections.generic.dictionary[string, string]'
            $ErrorProps.Add("SessionId", "$sessionId")
            $ErrorProps.Add("User", "$User")
            $ErrorProps.Add("Query events since", "$TimeBefore")
            $ErrorProps.Add("Function", "Get-Event_4624")
            TrackException -ErrorRecord $_ -Properties $ErrorProps -logAnalyticsConString $logAnalyticsConString;
        }
    }
    finally { }
}

<#
.SYNOPSIS
    ##############################################################################################################################
    # 5140 This event generates every time network share object was accessed.
    ##############################################################################################################################
#>

function Get-Event_5140_NetworkShareAccess {
    param(
        [Parameter(Mandatory = $true)]
        [string] $logAnalyticsConString,
        [Parameter(Mandatory = $true)]
        [string] $sessionId,
        [Parameter(Mandatory = $true)]
        [string] $User,
        [Parameter(Mandatory = $true)]
        [DateTime] $TimeBefore
    )
    Import-Module -Name "$PSScriptRoot\EMCommon.psm1"
    Import-Module -Name "$PSScriptRoot\Telemetry\AITelemetry.psm1"
    $LogFilePath = "$PSScriptRoot\Telemetry\Logs.txt";

    try {
        $events = Get-WinEvent -FilterHashtable @{logname=$EventLogType.SecurityLogs; id=5140} -ErrorAction Stop `
            | Where-Object { (($_.properties[1].value -eq  $user) -and ($_.TimeCreated -ge $TimeBefore ))}
        if ($null -ne $events -and $events.count -gt 0) {
            $events | ForEach-Object { 
                $sendEvent = $_
                $EvProps = New-Object 'system.collections.generic.dictionary[string, string]'
                $EvProps.Add("SessionId", $sessionId)
                $EvProps.Add("EventType", "Connect")
                # Add metadata info about event to be useful
                $EvProps.Add("LogonSID", "$($sendEvent.properties[0].Value)")
                $EvProps.Add("UserName", "$($sendEvent.properties[1].Value)")
                $EvProps.Add("AccountDomain", "$($sendEvent.properties[3].Value)")
                $EvProps.Add("SourceAddress", "$($sendEvent.properties[5].Value)")

                Send-LogAnalyticsConnectEvents `
                    -eventName "$($sendEvent.Id) Connect Event" `
                    -Properties $EvProps `
                    -sendEvent $sendEvent `
                    -logAnalyticsConString $logAnalyticsConString;
            }
        }
    }
    catch {
        if ($_ -notlike "*No events were found*") { 
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: Exception Message: `n$_.Exception.Message"
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: ScriptStackTrace: `n$_.ScriptStackTrace"
            $LASTEXITCODE = 1
            $ErrorProps = New-Object 'system.collections.generic.dictionary[string, string]'
            $ErrorProps.Add("SessionId", "$sessionId")
            $ErrorProps.Add("User", "$User")
            $ErrorProps.Add("Query events since", "$TimeBefore")
            $ErrorProps.Add("Function", "Get-Event_5140_NetworkShareAccess")
            TrackException -ErrorRecord $_ -Properties $ErrorProps -logAnalyticsConString $logAnalyticsConString;
        }
    }
    finally { }
}


<#
.SYNOPSIS
    ##############################################################################################################################
    # 4801 This event is generated when workstation was unlocked.
    ##############################################################################################################################
#>

function Get-Event_4801_MachineUnlocked {
    param(
        [Parameter(Mandatory = $true)]
        [string] $logAnalyticsConString,
        [Parameter(Mandatory = $true)]
        [string] $sessionId,
        [Parameter(Mandatory = $true)]
        [string] $User,
        [Parameter(Mandatory = $true)]
        [DateTime] $TimeBefore
    )
    Import-Module -Name "$PSScriptRoot\EMCommon.psm1"
    Import-Module -Name "$PSScriptRoot\Telemetry\AITelemetry.psm1"
    $LogFilePath = "$PSScriptRoot\Telemetry\Logs.txt";

    try {
        $events = Get-WinEvent -FilterHashtable @{logname=$EventLogType.SecurityLogs; id=4801} -ErrorAction Stop `
            | Where-Object { (($_.properties[1].Value -eq  $User) -and ($_.TimeCreated -ge $TimeBefore ))}
        if ($null -ne $events -and $events.count -gt 0) {
            $events    | ForEach-Object {
                $sendEvent = $_
                $EvProps = New-Object 'system.collections.generic.dictionary[string, string]'
                $EvProps.Add("SessionId", "$sessionId")
                $EvProps.Add("EventType", "Connect")
                # Add metadata info about event to be useful
                $EvProps.Add("LogonSID", "$($sendEvent.properties[0].Value)")
                $EvProps.Add("UserName", "$($sendEvent.properties[1].Value)")
                $EvProps.Add("AccountDomain", "$($sendEvent.properties[3].Value)")
                
                Send-LogAnalyticsConnectEvents `
                    -eventName "$($sendEvent.Id) Connect Event" `
                    -Properties $EvProps `
                    -sendEvent $sendEvent `
                    -logAnalyticsConString $logAnalyticsConString;
            }
        }
    }
    catch {
        if ($_ -notlike "*No events were found*") { 
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: Exception Message: `n$_.Exception.Message"
            Add-Content -Path $LogFilePath -Value "$(get-date -UFormat %c) :: ScriptStackTrace: `n$_.ScriptStackTrace"
            $LASTEXITCODE = 1
            $ErrorProps = New-Object 'system.collections.generic.dictionary[string, string]'
            $ErrorProps.Add("SessionId", "$sessionId")
            $ErrorProps.Add("User", "$User")
            $ErrorProps.Add("Query events since", "$TimeBefore")
            $ErrorProps.Add("Function", "Get-Event_4801_MachineUnlocked")
            TrackException -ErrorRecord $_ -Properties $ErrorProps -logAnalyticsConString $logAnalyticsConString;
        }
    }
    finally { }
}