Collect PowerShell logs
This document explains how to collect PowerShell logs to Google Security Operations by using Bindplane. The parser transforms raw Microsoft PowerShell logs into a unified data model (UDM). It first extracts fields from the raw log message, normalizes them into UDM fields, and then enriches the data with additional context based on specific event IDs, ultimately creating a structured UDM event for security analysis.
Before you begin
- Ensure that you have a Google SecOps instance.
- Ensure that you have a Windows 2016 or later.
- If running behind a proxy, ensure firewall ports are open.
Get Google SecOps ingestion authentication file
- Sign in to the Google SecOps console.
- Go to SIEM Settings > Collection Agents.
- Download the Ingestion Authentication File. Save the file securely on the system where Bindplane will be installed.
Get Google SecOps customer ID
- Sign in to the Google SecOps console.
- Go to SIEM Settings > Profile.
- Copy and save the Customer IDfrom the Organization Detailssection.
Install the Bindplane agent on Windows
- Open the Command Promptor PowerShellas an administrator.
-  Run the following command: msiexec / i "https://github.com/observIQ/bindplane-agent/releases/latest/download/observiq-otel-collector.msi" / quiet
Additional installation resources
- For additional installation options, consult this installation guide .
Configure the Bindplane agent to ingest Syslog and send to Google SecOps
- Before configuring the YAML file, stop the observIQ Distro for Open Telemetry CollectorServicein the Services Panel.
-  Access the configuration file: - Locate the config.yamlfile. Typically, it's in the/etc/bindplane-agent/directory on Linux or in the installation directory on Windows.
- Open the file using a text editor (for example, nano,vi, or Notepad).
 
- Locate the 
-  Edit the config.yamlfile as follows:receivers : windowseventlog/powershell : channel : Microsoft-Windows-PowerShell/Operational max_reads : 100 poll_interval : 5s raw : true start_at : end processors : batch : exporters : chronicle/powershell : endpoint : malachiteingestion-pa.googleapis.com # Adjust the path to the credentials file you downloaded in Step 1 creds : '/path/to/ingestion-authentication-file.json' log_type : 'POWERSHELL' override_log_type : false raw_log_field : body customer_id : '<customer_id>' service : pipelines : logs/winpowershell : receivers : - windowseventlog/powershell processors : [ batch ] exporters : [ chronicle/powershell ]
-  Replace <customer_id>with the actual customer ID.
-  Update /path/to/ingestion-authentication-file.jsonto the path where the authentication file was saved in the Get Google SecOps ingestion authentication file section.
-  After saving the config.yamlfile, starttheobservIQ Distro for Open Telemetry CollectorService.
Restart the Bindplane agent to apply the changes
-  To restart the Bindplane agent in Windows, you can either use the Servicesconsole or enter the following command: net stop BindPlaneAgent && net start BindPlaneAgent
UDM Mapping Table
| Log Field | UDM Mapping | Logic | 
|---|---|---|
|   
AccountName | principal.user.userid | Directly mapped from the AccountNamefield in the raw log. | 
|   
ActivityID | security_result.detection_fields[0].value | Directly mapped from the ActivityIDfield in the raw log. The curly braces are removed. | 
|   
Channel | Not mapped to the IDM object. | |
|   
collection_time.nanos | Not mapped to the IDM object. | |
|   
collection_time.seconds | Not mapped to the IDM object. | |
|   
Command | Not mapped to the IDM object. | |
|   
CommandLine | Not mapped to the IDM object. | |
|   
Computer | principal.hostname | Directly mapped from the Computerfield in the raw log if present. | 
|   
ContextInfo | Not mapped to the IDM object. | |
|   
ContextInfo_Command Name | security_result.detection_fields[0].value | Directly mapped from the ContextInfo_Command Namefield in the raw log if present. | 
|   
ContextInfo_Command Type | security_result.detection_fields[1].value | Directly mapped from the ContextInfo_Command Typefield in the raw log if present. | 
|   
ContextInfo_Host Application | target.process.command_line | Directly mapped from the ContextInfo_Host Applicationfield in the raw log ifpowershell.Host Applicationis not present. | 
|   
ContextInfo_Host ID | target.asset.asset_id | Directly mapped from the ContextInfo_Host IDfield in the raw log ifpowershell.Host IDis not present. The value is prefixed withHost ID:. | 
|   
ContextInfo_Host Name | target.hostname | Directly mapped from the ContextInfo_Host Namefield in the raw log ifpowershell.Host Nameis not present. | 
|   
ContextInfo_Script Name | target.process.file.full_path | Directly mapped from the ContextInfo_Script Namefield in the raw log ifscript_nameis not present. | 
|   
ContextInfo_Sequence Number | security_result.detection_fields[2].value | Directly mapped from the ContextInfo_Sequence Numberfield in the raw log if present. Converted to a string. | 
|   
ContextInfo_Severity | Not mapped to the IDM object. | |
|   
create_time.nanos | Not mapped to the IDM object. | |
|   
create_time.seconds | Not mapped to the IDM object. | |
|   
customer_id | Not mapped to the IDM object. | |
|   
data | Not mapped to the IDM object. | |
|   
Data | security_result.detection_fields[0].value | Directly mapped from the Datafield in the raw log if present. | 
|   
Data_1 | security_result.detection_fields[1].value | Directly mapped from the Data_1field in the raw log if present. | 
|   
Data_2 | security_result.detection_fields[2].value | Directly mapped from the Data_2field in the raw log if present. | 
|   
Domain | principal.administrative_domain | Directly mapped from the Domainfield in the raw log. | 
|   
entries | Not mapped to the IDM object. | |
|   
ERROR_EVT_UNRESOLVED | Not mapped to the IDM object. | |
|   
EventCategory | Not mapped to the IDM object. | |
|   
EventData | Not mapped to the IDM object. | |
|   
EventID | metadata.product_event_type, security_result.rule_name | Directly mapped from the EventIDfield in the raw log. The value is prefixed withEventID:for thesecurity_result.rule_namefield. | 
|   
EventLevel | Not mapped to the IDM object. | |
|   
EventLevelName | security_result.severity | Mapped based on the value of EventLevelName:- Informationmaps toINFORMATIONAL.- Verbosemaps toLOW. | 
|   
EventLog | Not mapped to the IDM object. | |
|   
EventReceivedTime | Not mapped to the IDM object. | |
|   
EventType | Not mapped to the IDM object. | |
|   
EventTime | metadata.event_timestamp | Used to extract the timestamp if present. | 
|   
ExecutionProcessID | principal.process.pid | Directly mapped from the ExecutionProcessIDfield in the raw log if present and not empty or 0. Converted to a string. | 
|   
ExecutionThreadID | security_result.detection_fields[2].value | Directly mapped from the ExecutionThreadIDfield in the raw log if present and not empty or 0. Converted to a string. | 
|   
File | target.process.file.full_path | Directly mapped from the Filefield in the raw log if present. | 
|   
Host Application | Not mapped to the IDM object. | |
|   
HostApplication | Not mapped to the IDM object. | |
|   
Hostname | principal.hostname | Directly mapped from the Hostnamefield in the raw log. | 
|   
id | Not mapped to the IDM object. | |
|   
Keywords | Not mapped to the IDM object. | |
|   
log_type | metadata.log_type | Directly mapped from the log_typefield in the raw log. | 
|   
Machine | principal.asset.asset_id, principal.asset.platform_software.platform_version | The Machinefield is parsed to extract the machine ID and platform information. The machine ID is prefixed withMachine ID:. The platform is mapped to the UDM enum based on the value:- winmaps toWINDOWS.- macmaps toMAC.- linmaps toLINUX.- Other values map to UNKNOWN_PLATFORM. | 
|   
ManagementGroupName | additional.fields[0].value.string_value | Directly mapped from the ManagementGroupNamefield in the raw log if present. | 
|   
Message.EventTime | metadata.event_timestamp | Used to extract the timestamp if present. Converted to a string. | 
|   
Message.Message | security_result.description | Directly mapped from the Message.Messagefield in the raw log ifEventIDis in [403,4103,4104] andmessage_message_not_found. Carriage returns and tabs are replaced with commas. | 
|   
Message | security_result.description | Directly mapped from the Messagefield in the raw log if present. | 
|   
MessageNumber | Not mapped to the IDM object. | |
|   
MessageSourceAddress | principal.ip | Directly mapped from the MessageSourceAddressfield in the raw log if present. | 
|   
MessageTotal | Not mapped to the IDM object. | |
|   
MG | Not mapped to the IDM object. | |
|   
Opcode | metadata.description | Directly mapped from the Opcodefield in the raw log. | 
|   
OpcodeValue | Not mapped to the IDM object. | |
|   
Output | security_result.detection_fields[0].value | Directly mapped from the Outputfield in the raw log if present. | 
|   
powershell.Command Name | security_result.detection_fields[0].value | Directly mapped from the powershell.Command Namefield if present. | 
|   
powershell.Command Type | security_result.detection_fields[1].value | Directly mapped from the powershell.Command Typefield if present. | 
|   
powershell.Host Application | target.process.command_line | Directly mapped from the powershell.Host Applicationfield in the raw log if present. | 
|   
powershell.Host ID | target.asset.asset_id | Directly mapped from the powershell.Host IDfield in the raw log if present. The value is prefixed withHost ID:. | 
|   
powershell.Host Name | target.hostname | Directly mapped from the powershell.Host Namefield in the raw log if present. | 
|   
powershell.HostApplication | target.process.command_line | Directly mapped from the powershell.HostApplicationfield in the raw log if present. | 
|   
powershell.HostId | target.asset.asset_id | Directly mapped from the powershell.HostIdfield in the raw log if present. The value is prefixed withHost ID:. | 
|   
powershell.HostName | target.hostname | Directly mapped from the powershell.HostNamefield in the raw log if present. | 
|   
powershell.Script Name | target.process.file.full_path | Directly mapped from the powershell.Script Namefield in the raw log if present. | 
|   
powershell.ScriptName | target.process.file.full_path | Directly mapped from the powershell.ScriptNamefield in the raw log if present. | 
|   
powershell.Sequence Number | security_result.detection_fields[2].value | Directly mapped from the powershell.Sequence Numberfield in the raw log if present. | 
|   
powershell.SequenceNumber | security_result.detection_fields[0].value | Directly mapped from the powershell.SequenceNumberfield in the raw log if present. | 
|   
powershell.UserId | principal.user.userid | Directly mapped from the powershell.UserIdfield in the raw log if present. | 
|   
Process ID | principal.process.pid | Directly mapped from the Process IDfield in the raw log ifExecutionProcessIDandProcessIDare not present or empty or 0. Converted to a string. | 
|   
ProcessID | principal.process.pid | Directly mapped from the ProcessIDfield in the raw log ifExecutionProcessIDis not present or empty or 0. Converted to a string. | 
|   
ProviderGuid | metadata.product_deployment_id | Directly mapped from the ProviderGuidfield in the raw log. The curly braces are removed. | 
|   
PSEdition | Not mapped to the IDM object. | |
|   
PSRemotingProtocolVersion | Not mapped to the IDM object. | |
|   
PSVersion | Not mapped to the IDM object. | |
|   
RecordNumber | metadata.product_log_id | Directly mapped from the RecordNumberfield in the raw log. Converted to a string. | 
|   
RenderedDescription | security_result.description | Directly mapped from the RenderedDescriptionfield in the raw log if present. | 
|   
RunAs User | Not mapped to the IDM object. | |
|   
ScriptBlockId | Not mapped to the IDM object. | |
|   
ScriptBlockText | security_result.detection_fields[0].value | Directly mapped from the ScriptBlockTextfield in the raw log if present. | 
|   
ScriptBlock ID | Not mapped to the IDM object. | |
|   
Severity | security_result.severity, security_result.severity_details | Mapped based on the value of Severity:- verboseorinfomaps toLOW.- warnorerrmaps toMEDIUM.- critmaps toHIGH.The raw value is also mapped to security_result.severity_details. | 
|   
source.collector_id | Not mapped to the IDM object. | |
|   
source.customer_id | Not mapped to the IDM object. | |
|   
Source | additional.fields[1].value.string_value | Directly mapped from the Sourcefield in the raw log if present. | 
|   
SourceModuleName | principal.resource.name | Directly mapped from the SourceModuleNamefield in the raw log. | 
|   
SourceModuleType | principal.resource.resource_subtype | Directly mapped from the SourceModuleTypefield in the raw log. | 
|   
SourceName | metadata.product_name | Directly mapped from the SourceNamefield in the raw log. | 
|   
start_time.nanos | Not mapped to the IDM object. | |
|   
start_time.seconds | Not mapped to the IDM object. | |
|   
TenantId | additional.fields[2].value.string_value | Directly mapped from the TenantIdfield in the raw log if present. | 
|   
ThreadID | Not mapped to the IDM object. | |
|   
timestamp.nanos | Not mapped to the IDM object. | |
|   
timestamp.seconds | Not mapped to the IDM object. | |
|   
type | Not mapped to the IDM object. | |
|   
UserID | principal.user.windows_sid | Directly mapped from the UserIDfield in the raw log. | 
|   
Username | principal.user.userid | Directly mapped from the Usernamefield in the raw log ifAccountNameis not present. | 
|  | metadata.vendor_name | Set to Microsoft. | 
|  | metadata.event_type | Set to PROCESS_LAUNCHifEventIDis4104and_Pathis present inMessage, or ifEventIDis4103, or ifEventIDis in [800,600,400] andpowershell.ScriptNameandpowershell.HostApplicationare present. Set toPROCESS_TERMINATIONifEventIDis403and_HostApplicationis present inMessage, or ifEventIDis403andNewEngineStateisStopped. Set toSTATUS_UPDATEifEventIDis4104and_Pathis not present inMessage, or ifEventIDis4103andno_value,script_nameis empty,script_name_not_found, andhost_application_not_foundare all true, or ifEventIDis53504, or ifEventIDis40962, or ifEventIDis40961, or ifEventIDis empty andMessageSourceAddressis present. Set toUSER_UNCATEGORIZEDifEventIDis empty andUsernameis present. Set toGENERIC_EVENTifEventIDis empty andMessageSourceAddressandUsernameare not present. | 
|  | metadata.product_name | Set to PowershellifSourceNameis not present. | 
|  | security_result.action | Set to ALLOW. | 
|  | security_result.detection_fields[0].key | Set to Activity ID. | 
|  | security_result.detection_fields[1].key | Set to Sequence Number. | 
|  | security_result.detection_fields[2].key | Set to ExecutionThreadID. | 
|  | additional.fields[0].key | Set to Management Group Name. | 
|  | additional.fields[1].key | Set to Source. | 
|  | additional.fields[2].key | Set to TenantId. | 
|  | principal.asset.platform_software.platform | Set to WINDOWSifplatform_softwarecontainswin,MACif it containsmac,LINUXif it containslin, andUNKNOWN_PLATFORMotherwise. | 
|  | target.process.file.full_path | Set to _PathifEventIDis4104and_Pathis present inMessage. Set tofile_pathifEventIDis4104andfile_pathis present inMessage. Set to_HostApplicationifEventIDis403and_HostApplicationis present inMessage. | 
Need more help? Get answers from Community members and Google SecOps professionals.

