Windows.Applications.IISLogs

This artifact enables grep of IISLogs.

Parameters include SearchRegex and WhitelistRegex as regex terms and MoreRecentThan as timestamp.

Hint: Make sure to get the right location of the log files as they are often stored at different non-default locations.

Hint 2: MoreRecentThan filter is only applied to the Last Modified Time of files returned by the IISLogFiles glob. This improves the artefact’s performance on systems with many log files. Use the SearchRegex filter for filtering on a per line basis.

For example, a regex like 2025-07-2[1-5] will efficiently recover lines with ISO times between the 21st and 25th July 2025.


name: Windows.Applications.IISLogs
description: |
  This artifact enables grep of IISLogs.

  Parameters include SearchRegex and WhitelistRegex as regex terms and
  MoreRecentThan as timestamp.

  **Hint:** Make sure to get the right location of the log files as
    they are often stored at different non-default locations.

  **Hint 2:** MoreRecentThan filter is only applied to the Last
    Modified Time of files returned by the IISLogFiles glob. This
    improves the artefact's performance on systems with many log
    files. Use the SearchRegex filter for filtering on a per line
    basis.

    For example, a regex like `2025-07-2[1-5]` will efficiently
    recover lines with ISO times between the 21st and 25th July 2025.

author: "Matt Green - @mgreen27, Updated by Stephan Mikiss"

parameters:
  - name: IISLogFiles
    default: '*:/inetpub/logs/**3/*.log'
  - name: MoreRecentThan
    default: ""
    type: timestamp
  - name: SearchRegex
    description: "Regex of strings to search in line."
    default: ' POST '
    type: regex
  - name: WhitelistRegex
    description: "Regex of strings to leave out of output."
    default:
    type: regex

sources:
  - precondition: SELECT OS From info() where OS = 'windows'

    query: |
      LET files = SELECT OSPath,Mtime AS MTime FROM glob(globs=IISLogFiles)

      LET more_recent = SELECT * FROM if(
        condition=MoreRecentThan,
        then={
          SELECT * FROM files
          WHERE MTime > MoreRecentThan
        }, else=files)

      SELECT * FROM foreach(row=more_recent,
          query={
              SELECT Line, OSPath FROM parse_lines(filename=OSPath)
              WHERE
                Line =~ SearchRegex
                AND NOT if(condition= WhitelistRegex,
                    then= Line =~ WhitelistRegex,
                    else= FALSE)
          })

    notebook:
      - type: vql_suggestion
        name: IIS Groks
        template: |
            /*
            ### IIS grok

            Note:  IIS doesn't have a standard logging format so we have added some
            suggestions. Comment in preferred or add / modify your own.
            */

            LET target_grok = "%{TIMESTAMP_ISO8601:LogTimeStamp} %{IPORHOST:Site} %{WORD:Method} %{URIPATH:UriPath} %{NOTSPACE:QueryString} %{NUMBER:Port} %{NOTSPACE:Username} %{IPORHOST:Clienthost} %{NOTSPACE:Useragent} %{NOTSPACE:Referrer} %{NUMBER:Response} %{NUMBER:Subresponse} %{NUMBER:Win32status} %{NUMBER:Timetaken:int}"
            --LET target_grok = "%{TIMESTAMP_ISO8601:log_timestamp} %{IPORHOST:site} %{WORD:method} %{URIPATH:page} %{NOTSPACE:querystring} %{NUMBER:port} %{NOTSPACE:username} %{IPORHOST:clienthost} %{NOTSPACE:useragent} %{NOTSPACE:referer} %{NUMBER:response} %{NUMBER:subresponse} %{NUMBER:scstatus} %{NUMBER:timetaken:int}"
            --LET target_grok = "%{TIMESTAMP_ISO8601:log_timestamp} %{WORD:iisSite} %{NOTSPACE:computername} %{IPORHOST:site} %{WORD:method} %{URIPATH:page} %{NOTSPACE:querystring} %{NUMBER:port} %{NOTSPACE:username} %{IPORHOST:clienthost} %{NOTSPACE:protocol} %{NOTSPACE:useragent} %{NOTSPACE:referer} %{IPORHOST:cshost} %{NUMBER:response} %{NUMBER:subresponse} %{NUMBER:scstatus} %{NUMBER:bytessent:int} %{NUMBER:bytesrecvd:int} %{NUMBER:timetaken:int}"


            LET parsed = SELECT Fqdn, ClientId as _ClientId, Line as _Raw,
                  grok(data=Line,grok=target_grok) as GrokParsed
              FROM source()

            SELECT * FROM foreach(row=parsed,
                  query={ SELECT *, Fqdn, _Raw FROM GrokParsed })