Skip to main content

Path Parse

Parse Security

Synopsis

Splits a file path — Windows or Unix — into an object of its component parts.

Schema

- path_parse:
field: <ident>
description: <text>
if: <script>
ignore_failure: <boolean>
ignore_missing: <boolean>
on_failure: <processor[]>
on_success: <processor[]>
tag: <string>
target_field: <ident>

Configuration

The following fields are used to define the processor:

FieldRequiredDefaultDescription
fieldY-Field containing the path to parse
descriptionN-Explanatory note
ifN-Condition to run
ignore_failureNfalseSee Handling Failures
ignore_missingNfalseIf true, quietly exit if field doesn't exist
on_failureN-See Handling Failures
on_successN-See Handling Success
tagN-Identifier
disabledNfalseWhen true, the processor is skipped and the event continues to the next one. Lets you take a processor out of the path without removing its configuration
target_fieldNfieldField to store the component object. Defaults to field, replacing the path string

Details

The result is always an object with all seven keys present. A component that does not apply is an empty string rather than being absent, so a downstream reference never has to test for existence.

KeyContents
SchemeAnything before ://, empty for a plain path
RootPathThe drive specifier, such as C:. Empty on a Unix path
DirectoryPathEverything before the final separator
DirectoryNameThe last segment of DirectoryPath alone
FilenameThe final segment, without any alternate data stream
ExtensionText after the last dot in Filename, without the dot
AlternateDataStreamNameThe NTFS alternate data stream name, if one is present

The separator is detected, not configured. Whichever of \ or / occurs more often in the path wins, so mixed-separator paths — common in logs that have passed through more than one system — parse the way a reader would expect rather than requiring the source platform to be known in advance.

AlternateDataStreamName is the reason to reach for this processor on Windows telemetry. A colon after the first character of the filename separates an NTFS alternate data stream, so notepad.exe:evil.ps1 yields Filename: notepad.exe and AlternateDataStreamName: evil.ps1. Splitting on the separator alone would leave both stuck together in one value. The colon of a drive specifier is not mistaken for this, because a stream separator has to appear beyond the first character.

A leading dot does not make an extension: .bashrc has an empty Extension and is a filename in full.

Examples

A Windows Path

Splitting a full Windows path...

{
"file": {"path": "C:\\Windows\\System32\\drivers\\etc\\hosts"}
}
- path_parse:
field: file.path
target_field: file.parts

with every component present:

{
"file": {
"path": "C:\\Windows\\System32\\drivers\\etc\\hosts",
"parts": {
"Scheme": "",
"RootPath": "C:",
"DirectoryPath": "C:\\Windows\\System32\\drivers\\etc",
"DirectoryName": "etc",
"Filename": "hosts",
"Extension": "",
"AlternateDataStreamName": ""
}
}
}

An Alternate Data Stream

A colon past the first character separates an NTFS stream...

{
"file": {"path": "C:\\Users\\jsmith\\notepad.exe:evil.ps1"}
}
- path_parse:
field: file.path
target_field: file.parts

so the hidden stream lands in its own field:

{
"file": {
"path": "C:\\Users\\jsmith\\notepad.exe:evil.ps1",
"parts": {
"Scheme": "",
"RootPath": "C:",
"DirectoryPath": "C:\\Users\\jsmith",
"DirectoryName": "jsmith",
"Filename": "notepad.exe",
"Extension": "exe",
"AlternateDataStreamName": "evil.ps1"
}
}
}

A Unix Path

The separator is detected from the path itself...

{
"file": {"path": "/var/log/nginx/access.log"}
}
- path_parse:
field: file.path
target_field: file.parts

with RootPath empty, since there is no drive:

{
"file": {
"path": "/var/log/nginx/access.log",
"parts": {
"Scheme": "",
"RootPath": "",
"DirectoryPath": "/var/log/nginx",
"DirectoryName": "nginx",
"Filename": "access.log",
"Extension": "log",
"AlternateDataStreamName": ""
}
}
}

A Path With a Scheme

Anything before :// is lifted into Scheme...

{
"file": {"path": "smb://fileserver/share/report.xlsx"}
}
- path_parse:
field: file.path
target_field: file.parts

and the rest is parsed as an ordinary path:

{
"file": {
"path": "smb://fileserver/share/report.xlsx",
"parts": {
"Scheme": "smb",
"RootPath": "",
"DirectoryPath": "fileserver/share",
"DirectoryName": "share",
"Filename": "report.xlsx",
"Extension": "xlsx",
"AlternateDataStreamName": ""
}
}
}