Analyze User Logon Patterns And Activity

Summarize user authentication events across the environment using the groupBy() function

Query

flowchart LR; %%{init: {"flowchart": {"defaultRenderer": "elk"}} }%% repo{{Events}} 1[/Filter/] 2["Expression"] 3@{ shape: win-pane, label: "Table" } result{{Result Set}} repo --> 1 1 --> 2 2 --> 3 3 --> result
logscale
#event_simpleName=UserLogon
| groupBy([UserName, name, aid, aip, ComputerName, event_platform, LocalIP, LogonDomain, LogonServer, LogonType], function=[count(@timestamp), selectLast([@timestamp])])
| table([@timestamp, UserName, ComputerName, aid, aip, event_platform, LocalIP, LogonDomain, LogonType], limit=20000)

Introduction

The groupBy() function can be used to aggregate and analyze authentication events by grouping related logon information, providing insights into user access patterns and potential security anomalies.

In this example, the groupBy() function is used to analyze user logon events by aggregating authentication data across multiple systems, providing visibility into who is logging in, from where, and how often.

Example incoming data might look like this:

@timestamp#event_simpleNameUserNamenameaidaipComputerNameevent_platformLocalIPLogonDomainLogonServerLogonType
2025-11-05T10:15:00ZUserLogonjohn.doeJohn Doeaid12310.1.1.100DESKTOP-001Windows192.168.1.10CORPDC012
2025-11-05T10:16:00ZUserLogonjohn.doeJohn Doeaid12310.1.1.100DESKTOP-001Windows192.168.1.10CORPDC012
2025-11-05T10:20:00ZUserLogonjane.smithJane Smithaid12410.1.1.101LAPTOP-002Windows192.168.1.11CORPDC0110
2025-11-05T10:25:00ZUserLogonadmin.userAdmin Useraid12510.1.1.102SERVER-001Windows192.168.1.12CORPDC013
2025-11-05T10:30:00ZUserLogonjane.smithJane Smithaid12410.1.1.101LAPTOP-002Windows192.168.1.11CORPDC0110

Step-by-Step

  1. Starting with the source repository events.

  2. flowchart LR; %%{init: {"flowchart": {"defaultRenderer": "elk"}} }%% repo{{Events}} 1[/Filter/] 2["Expression"] 3@{ shape: win-pane, label: "Table" } result{{Result Set}} repo --> 1 1 --> 2 2 --> 3 3 --> result style 1 fill:#ff0000,stroke-width:4px,stroke:#000;
    logscale
    #event_simpleName=UserLogon

    Filters events to include only user logon events where #event_simpleName equals UserLogon.

  3. flowchart LR; %%{init: {"flowchart": {"defaultRenderer": "elk"}} }%% repo{{Events}} 1[/Filter/] 2["Expression"] 3@{ shape: win-pane, label: "Table" } result{{Result Set}} repo --> 1 1 --> 2 2 --> 3 3 --> result style 2 fill:#ff0000,stroke-width:4px,stroke:#000;
    logscale
    | groupBy([UserName, name, aid, aip, ComputerName, event_platform, LocalIP, LogonDomain, LogonServer, LogonType], function=[count(@timestamp), selectLast([@timestamp])])

    Groups logon events by multiple fields including user, system, and network information. For each group, it calculates two aggregate values:

    • The total count of logon events using count(@timestamp).

    • The most recent logon timestamp using selectLast([@timestamp]).

      Note that selectLast([@timestamp]) is equivalent to using max(@timestamp).

  4. flowchart LR; %%{init: {"flowchart": {"defaultRenderer": "elk"}} }%% repo{{Events}} 1[/Filter/] 2["Expression"] 3@{ shape: win-pane, label: "Table" } result{{Result Set}} repo --> 1 1 --> 2 2 --> 3 3 --> result style 3 fill:#ff0000,stroke-width:4px,stroke:#000;
    logscale
    | table([@timestamp, UserName, ComputerName, aid, aip, event_platform, LocalIP, LogonDomain, LogonType], limit=20000)

    Creates a table displaying key logon information, including timestamp, user details, system information, and logon type. The limit parameter is set to return up to 20,000 results.

  5. Event Result set.

Summary and Results

The query is used to analyze user authentication patterns by aggregating logon events and providing a comprehensive view of user access across the environment.

This query is useful, for example, to identify unusual logon patterns, monitor privileged account usage, and track user access across different systems.

Sample output from the incoming example data:

@timestampUserNameComputerNameaidaipevent_platformLocalIPLogonDomainLogonType_count
2025-11-05T10:16:00Zjohn.doeDESKTOP-001aid12310.1.1.100Windows192.168.1.10CORP22
2025-11-05T10:30:00Zjane.smithLAPTOP-002aid12410.1.1.101Windows192.168.1.11CORP102
2025-11-05T10:25:00Zadmin.userSERVER-001aid12510.1.1.102Windows192.168.1.12CORP31

Note that the _count field shows the number of logon events for each unique combination of grouped fields. The @timestamp shown is the most recent logon time for each group.

Different LogonType values indicate various authentication methods (for example, 2 for interactive, 3 for network, 10 for remote interactive).

The opposite query showing user logoff events might look like this:

logscale
#event_simpleName=UserLogoff
| groupBy([UserName, name, aid, aip, ComputerName, event_platform, LocalIP, LogonDomain, LogonServer, LogonType], function=[count(@timestamp), selectLast([@timestamp])])
| table([@timestamp, UserName, ComputerName, aid, aip, event_platform, LocalIP, LogonDomain, LogonType], limit=20000)