# Fortinet FortiNDR Cloud KQL Log Parser Installation This parser normalizes and unpacks dynamic log entries sent via Data Collection Rules into structured, queryable data columns matching your Microsoft Sentinel dashboards. ## Installation Instructions 1. Log in to the Azure Portal and navigate to your **Log Analytics Workspace** (or Microsoft Sentinel Workspace). 2. On the left navigation pane under the **General** section, click on **Logs**. 3. Copy the entire query block below and paste it into the clean query editor sheet. 4. Click on the **Save** button dropdown on the top toolbar and select **Save as function**. 5. Configure the function parameters exactly as shown: * **Function Name:** `Fortinet_FortiNDR_Cloud` * **Function Alias:** `Fortinet_FortiNDR_Cloud` * **Category:** `Microsoft Sentinel Parser` 6. Click **Save**. *(Note: The function alias will take up to 10-15 minutes to register natively inside your workspace across related workbook visualization panels).* ## KQL Query Block ```kql let FortiNDR_Cloud_suricata_view = view () { FortinetFortiNdrCloudRaw_CL | where LogTypeSuffix == "suricata" or column_ifexists('event_type', '') == "suricata" | extend parsed = parse_json(column_ifexists('RawData', '{}')) | extend su_timestamp=todatetime(coalesce(parsed.timestamp, TimeGenerated)), su_uuid=tostring(parsed.uuid), su_event_type=tostring(coalesce(parsed.event_type, 'suricata')), su_customer_id=tostring(parsed.customer_id), su_sensor_id=tostring(parsed.sensor_id), su_source=tostring(parsed.source), su_src_ip=tostring(parsed.src_ip), su_src_port=todouble(parsed.src_port), su_dst_ip=tostring(parsed.dest_ip), su_dst_port=todouble(parsed.dest_port), su_proto=tostring(parsed.proto), su_sig_id=todouble(parsed.alert.signature_id), su_sig_rev=todouble(parsed.alert.rev), su_sig_name=tostring(parsed.alert.signature), su_sig_category=tostring(parsed.alert.category), su_sig_severity=todouble(parsed.alert.severity), su_src_internal=tobool(parsed.src_ip_enrichments.internal), su_src_geo_lat=todouble(parsed.src_ip_enrichments.geo.location.lat), su_src_geo_lon=todouble(parsed.src_ip_enrichments.geo.location.lon), su_src_geo_country=tostring(parsed.src_ip_enrichments.geo.country), su_src_geo_subdivision=tostring(parsed.src_ip_enrichments.geo.subdivision), su_src_geo_city=tostring(parsed.src_ip_enrichments.geo.city), su_src_asn_asn=todouble(parsed.src_ip_enrichments.asn.asn), su_src_asn_org=tostring(parsed.src_ip_enrichments.asn.org), su_src_asn_isp=tostring(parsed.src_ip_enrichments.asn.isp), su_src_asn_asn_org=tostring(parsed.src_ip_enrichments.asn.asn_org), su_src_annotations_applications=tostring(parsed.src_ip_enrichments.annotations.applications), su_src_annotations_environments=tostring(parsed.src_ip_enrichments.annotations.environments), su_src_annotations_locations=tostring(parsed.src_ip_enrichments.annotations.locations), su_src_annotations_owners=tostring(parsed.src_ip_enrichments.annotations.owners), su_src_annotations_roles=tostring(parsed.src_ip_enrichments.annotations.roles), su_src_annotations_tags=tostring(parsed.src_ip_enrichments.annotations.tags), su_src_annotations_identified_assets=tostring(parsed.src_ip_enrichments.annotations.identified_assets), // Added mapped Source Device identities found in log results su_src_device_os_name=tostring(parsed.src_ip_enrichments.device_os_name), su_src_device_os_version=tostring(parsed.src_ip_enrichments.device_os_version), su_src_device_os_name_with_version=tostring(parsed.src_ip_enrichments.device_os_name_with_version), su_src_device_hostnames=tostring(parsed.src_ip_enrichments.device_hostnames), su_src_device_data_timestamp=tostring(parsed.src_ip_enrichments.device_data_timestamp), su_src_device_last_logon=tostring(parsed.src_ip_enrichments.device_last_logon), su_src_device_last_logoff=tostring(parsed.src_ip_enrichments.device_last_logoff), su_dst_internal=tobool(parsed.dst_ip_enrichments.internal), su_dst_geo_lat=todouble(parsed.dst_ip_enrichments.geo.location.lat), su_dst_geo_lon=todouble(parsed.dst_ip_enrichments.geo.location.lon), su_dst_geo_country=tostring(parsed.dst_ip_enrichments.geo.country), su_dst_geo_subdivision=tostring(parsed.dst_ip_enrichments.geo.subdivision), su_dst_geo_city=tostring(parsed.dst_ip_enrichments.geo.city), su_dst_asn_asn=todouble(parsed.dst_ip_enrichments.asn.asn), su_dst_asn_org=tostring(parsed.dst_ip_enrichments.asn.org), su_dst_asn_isp=tostring(parsed.dst_ip_enrichments.asn.isp), su_dst_asn_asn_org=tostring(parsed.dst_ip_enrichments.asn.asn_org), su_dst_annotations_applications=tostring(parsed.dst_ip_enrichments.annotations.applications), su_dst_annotations_environments=tostring(parsed.dst_ip_enrichments.annotations.environments), su_dst_annotations_locations=tostring(parsed.dst_ip_enrichments.annotations.locations), su_dst_annotations_owners=tostring(parsed.dst_ip_enrichments.annotations.owners), su_dst_annotations_roles=tostring(parsed.dst_ip_enrichments.annotations.roles), su_dst_annotations_tags=tostring(parsed.dst_ip_enrichments.annotations.tags), su_dst_annotations_identified_assets=tostring(parsed.dst_ip_enrichments.annotations.identified_assets), // Added mapped Destination Device identities found in log results su_dst_device_os_name=tostring(parsed.dst_ip_enrichments.device_os_name), su_dst_device_os_version=tostring(parsed.dst_ip_enrichments.device_os_version), su_dst_device_os_name_with_version=tostring(parsed.dst_ip_enrichments.device_os_name_with_version), su_dst_device_hostnames=tostring(parsed.dst_ip_enrichments.device_hostnames), su_dst_device_data_timestamp=tostring(parsed.dst_ip_enrichments.device_data_timestamp), su_dst_device_last_logon=tostring(parsed.dst_ip_enrichments.device_last_logon), su_dst_device_last_logoff=tostring(parsed.dst_ip_enrichments.device_last_logoff), su_geo_distance=todouble(parsed.geo_distance), su_http_status=todouble(parsed.http.status), su_http_protocol=tostring(parsed.http.protocol), su_http_url=tostring(parsed.http.url), su_http_hostname=tostring(parsed.http.hostname), su_http_host_internal=tobool(parsed.http_hostname_enrichments.ip_enrichments.internal), su_http_host_geo_lat=todouble(parsed.http_hostname_enrichments.ip_enrichments.geo.location.lat), su_http_host_geo_lon=todouble(parsed.http_hostname_enrichments.ip_enrichments.geo.location.lon), su_http_host_geo_subdivision=tostring(parsed.http_hostname_enrichments.ip_enrichments.geo.subdivision), su_http_host_geo_city=tostring(parsed.http_hostname_enrichments.ip_enrichments.geo.city), su_http_host_asn_asn=todouble(parsed.http_hostname_enrichments.ip_enrichments.asn.asn), su_http_host_asn_org=tostring(parsed.http_hostname_enrichments.ip_enrichments.asn.org), su_http_host_asn_isp=tostring(parsed.http_hostname_enrichments.ip_enrichments.asn.isp), su_http_host_asn_asn_org=tostring(parsed.http_hostname_enrichments.ip_enrichments.asn.asn_org), su_http_host_geo_country=tostring(parsed.http_hostname_enrichments.ip_enrichments.geo.country), su_http_host_annotations_applications=tostring(parsed.http_hostname_enrichments.ip_enrichments.annotations.applications), su_http_host_annotations_environments=tostring(parsed.http_hostname_enrichments.ip_enrichments.annotations.environments), su_http_host_annotations_locations=tostring(parsed.http_hostname_enrichments.ip_enrichments.annotations_locations), su_http_host_annotations_owners=tostring(parsed.http_hostname_enrichments.ip_enrichments.annotations_owners), su_http_host_annotations_roles=tostring(parsed.http_hostname_enrichments.ip_enrichments.annotations_roles), su_http_host_annotations_tags=tostring(parsed.http_hostname_enrichments.ip_enrichments.annotations_tags), su_http_host_domain_entropy=todouble(parsed.http_hostname_enrichments.domain_enrichments.domain_entropy), su_http_length=todouble(parsed.http.length), su_http_method=tostring(parsed.http.http_method), su_http_content_type=tostring(parsed.http.http_content_type), su_http_refer=tostring(parsed.http.http_refer), su_http_user_agent=tostring(parsed.http.http_user_agent), su_http_redirect=tostring(parsed.http.redirect), su_http_xtf=tostring(parsed.http.xff), su_payload=tostring(parsed.payload), su_intel=tostring(parsed.intel), Type="FncEventsSuricata_CL" | project TimeGenerated, su_timestamp, su_event_type, su_src_ip, su_src_port, su_dst_ip, su_dst_port, su_intel, su_sig_name, su_sig_id, su_sig_rev, su_sig_category, su_sig_severity, su_payload, su_source, su_proto, su_sensor_id, su_src_internal, su_src_geo_lat, su_src_geo_lon, su_src_geo_country, su_src_geo_subdivision, su_src_geo_city, su_src_asn_asn, su_src_asn_org, su_src_asn_isp, su_src_asn_asn_org, su_src_annotations_applications, su_src_annotations_environments, su_src_annotations_locations, su_src_annotations_owners, su_src_annotations_roles, su_src_annotations_tags, su_src_annotations_identified_assets, su_src_device_os_name, su_src_device_os_version, su_src_device_os_name_with_version, su_src_device_hostnames, su_src_device_data_timestamp, su_src_device_last_logon, su_src_device_last_logoff, su_dst_internal, su_dst_geo_lat, su_dst_geo_lon, su_dst_geo_country, su_dst_geo_subdivision, su_dst_geo_city, su_dst_asn_asn, su_dst_asn_org, su_dst_asn_isp, su_dst_asn_asn_org, su_dst_annotations_applications, su_dst_annotations_environments, su_dst_annotations_locations, su_dst_annotations_owners, su_dst_annotations_roles, su_dst_annotations_tags, su_dst_annotations_identified_assets, su_dst_device_os_name, su_dst_device_os_version, su_dst_device_os_name_with_version, su_dst_device_hostnames, su_dst_device_data_timestamp, su_dst_device_last_logon, su_dst_device_last_logoff, su_geo_distance, su_http_status, su_http_protocol, su_http_url, su_http_hostname, su_http_host_internal, su_http_host_geo_lat, su_http_host_geo_lon, su_http_host_geo_country, su_http_host_geo_subdivision, su_http_host_geo_city, su_http_host_asn_asn, su_http_host_asn_org, su_http_host_asn_isp, su_http_host_asn_asn_org, su_http_host_annotations_applications, su_http_host_annotations_environments, su_http_host_annotations_locations, su_http_host_annotations_owners, su_http_host_annotations_roles, su_http_host_annotations_tags, su_http_host_domain_entropy, su_http_length, su_http_method, su_http_content_type, su_http_refer, su_http_user_agent, su_http_redirect, su_http_xtf, su_uuid, su_customer_id, Type }; let FortiNDR_Cloud_observation_view = view () { FortinetFortiNdrCloudRaw_CL | where LogTypeSuffix == "observation" or column_ifexists('event_type', '') == "observation" | extend parsed = parse_json(column_ifexists('RawData', '{}')) | extend ob_timestamp=todatetime(coalesce(parsed.timestamp, TimeGenerated)), ob_uuid=tostring(parsed.uuid), ob_event_type=tostring(coalesce(parsed.event_type, 'observation')), ob_customer_id=tostring(parsed.customer_id), ob_sensor_id=tostring(parsed.sensor_id), ob_source=tostring(parsed.source), ob_evidence_start_timestamp=tostring(parsed.evidence_start_timestamp), ob_evidence_end_timestamp=tostring(parsed.evidence_end_timestamp), ob_observation_uuid=tostring(parsed.observation_uuid), ob_observation_title=tostring(parsed['title']), ob_confidence=tostring(parsed.confidence), ob_src_ip=tostring(parsed.src_ip), ob_dst_ip=tostring(parsed.dst_ip), ob_src_internal=tobool(parsed.src_ip_enrichments.internal), ob_src_geo_lat=todouble(parsed.src_ip_enrichments.geo.location.lat), ob_src_geo_lon=todouble(parsed.src_ip_enrichments.geo.location.lon), ob_src_geo_country=tostring(parsed.src_ip_enrichments.geo.country), ob_src_geo_subdivision=tostring(parsed.src_ip_enrichments.geo.subdivision), ob_src_geo_city=tostring(parsed.src_ip_enrichments.geo.city), ob_src_asn_asn=todouble(parsed.src_ip_enrichments.asn.asn), ob_src_asn_org=tostring(parsed.src_ip_enrichments.asn.org), ob_src_asn_isp=tostring(parsed.src_ip_enrichments.asn.isp), ob_src_asn_asn_org=tostring(parsed.src_ip_enrichments.asn.asn_org), ob_src_annotations_applications=tostring(parsed.src_ip_enrichments.annotations.applications), ob_src_annotations_environments=tostring(parsed.src_ip_enrichments.annotations.environments), ob_src_annotations_locations=tostring(parsed.src_ip_enrichments.annotations.locations), ob_src_annotations_owners=tostring(parsed.src_ip_enrichments.annotations.owners), ob_src_annotations_roles=tostring(parsed.src_ip_enrichments.annotations.roles), ob_src_annotations_tags=tostring(parsed.src_ip_enrichments.annotations.tags), ob_src_annotations_identified_assets=tostring(parsed.src_ip_enrichments.annotations.identified_assets), // Added mapped Observation Source Device context ob_src_device_os_name=tostring(parsed.src_ip_enrichments.device_os_name), ob_src_device_os_version=tostring(parsed.src_ip_enrichments.device_os_version), ob_src_device_os_name_with_version=tostring(parsed.src_ip_enrichments.device_os_name_with_version), ob_src_device_hostnames=tostring(parsed.src_ip_enrichments.device_hostnames), ob_src_device_data_timestamp=tostring(parsed.src_ip_enrichments.device_data_timestamp), ob_src_device_last_logon=tostring(parsed.src_ip_enrichments.device_last_logon), ob_src_device_last_logoff=tostring(parsed.src_ip_enrichments.device_last_logoff), ob_dst_internal=tobool(parsed.dst_ip_enrichments.internal), ob_dst_geo_lat=todouble(parsed.dst_ip_enrichments.geo.location.lat), ob_dst_geo_lon=todouble(parsed.dst_ip_enrichments.geo.location.lon), ob_dst_geo_country=tostring(parsed.dst_ip_enrichments.geo.country), ob_dst_geo_subdivision=tostring(parsed.dst_ip_enrichments.geo.subdivision), ob_dst_geo_city=tostring(parsed.dst_ip_enrichments.geo.city), ob_dst_asn_asn=todouble(parsed.dst_ip_enrichments.asn.asn), ob_dst_asn_org=tostring(parsed.dst_ip_enrichments.asn.org), ob_dst_asn_isp=tostring(parsed.dst_ip_enrichments.asn.isp), ob_dst_asn_asn_org=tostring(parsed.dst_ip_enrichments.asn.asn_org), ob_dst_annotations_applications=tostring(parsed.dst_ip_enrichments.annotations.applications), ob_dst_annotations_environments=tostring(parsed.dst_ip_enrichments.annotations.environments), ob_dst_annotations_locations=tostring(parsed.dst_ip_enrichments.annotations.locations), ob_dst_annotations_owners=tostring(parsed.dst_ip_enrichments.annotations.owners), ob_dst_annotations_roles=tostring(parsed.dst_ip_enrichments.annotations.roles), ob_dst_annotations_tags=tostring(parsed.dst_ip_enrichments.annotations.tags), ob_dst_annotations_identified_assets=tostring(parsed.dst_ip_enrichments.annotations.identified_assets), // Added mapped Observation Destination Device context ob_dst_device_os_name=tostring(parsed.dst_ip_enrichments.device_os_name), ob_dst_device_os_version=tostring(parsed.dst_ip_enrichments.device_os_version), ob_dst_device_os_name_with_version=tostring(parsed.dst_ip_enrichments.device_os_name_with_version), ob_dst_device_hostnames=tostring(parsed.dst_ip_enrichments.device_hostnames), ob_dst_device_data_timestamp=tostring(parsed.dst_ip_enrichments.device_data_timestamp), ob_dst_device_last_logon=tostring(parsed.dst_ip_enrichments.device_last_logon), ob_dst_device_last_logoff=tostring(parsed.dst_ip_enrichments.device_last_logoff), ob_geo_distance=todouble(parsed.geo_distance), ob_sensor_ids=tostring(parsed.sensor_ids), ob_evidence_iql=tostring(parsed.evidence_iql), ob_description=tostring(parsed.description), ob_context=tostring(parsed.context), ob_class=tostring(parsed['class']), ob_intel=tostring(parsed.intel), ob_category=tostring(parsed['Category']), Type="FncEventsObservation_CL" | project TimeGenerated, ob_timestamp, ob_observation_title, ob_confidence, ob_category, ob_class, ob_context, ob_evidence_iql, ob_evidence_end_timestamp, ob_evidence_start_timestamp, ob_description, ob_observation_uuid, ob_sensor_ids, ob_event_type, ob_src_ip, ob_dst_ip, ob_intel, ob_source, ob_sensor_id, ob_src_internal, ob_src_geo_lat, ob_src_geo_lon, ob_src_geo_country, ob_src_geo_subdivision, ob_src_geo_city, ob_src_asn_asn, ob_src_asn_org, ob_src_asn_isp, ob_src_asn_asn_org, ob_src_annotations_applications, ob_src_annotations_environments, ob_src_annotations_locations, ob_src_annotations_owners, ob_src_annotations_roles, ob_src_annotations_tags, ob_src_annotations_identified_assets, ob_src_device_os_name, ob_src_device_os_version, ob_src_device_os_name_with_version, ob_src_device_hostnames, ob_src_device_data_timestamp, ob_src_device_last_logon, ob_src_device_last_logoff, ob_dst_internal, ob_dst_geo_lat, ob_dst_geo_lon, ob_dst_geo_country, ob_dst_geo_subdivision, ob_dst_geo_city, ob_dst_asn_asn, ob_dst_asn_org, ob_dst_asn_isp, ob_dst_asn_asn_org, ob_dst_annotations_applications, ob_dst_annotations_environments, ob_dst_annotations_locations, ob_dst_annotations_owners, ob_dst_annotations_roles, ob_dst_annotations_tags, ob_dst_annotations_identified_assets, ob_dst_device_os_name, ob_dst_device_os_version, ob_dst_device_os_name_with_version, ob_dst_device_hostnames, ob_dst_device_data_timestamp, ob_dst_device_last_logon, ob_dst_device_last_logoff, ob_geo_distance, ob_uuid, ob_customer_id, Type }; let FortiNDR_Cloud_detections_view = view () { FortinetFortiNdrCloudRaw_CL | where LogTypeSuffix == "detections" or LogTypeSuffix == "detection" or column_ifexists('event_type', '') == "detection" | extend parsed = parse_json(column_ifexists('RawData', '{}')) | extend de_account_id=tostring(parsed.account_uuid), de_device_ip=tostring(parsed.device_ip), de_rule_name=tostring(parsed.rule_name), de_severity=tostring(parsed.rule_severity), de_confidence=tostring(parsed.rule_confidence), de_sensor_id=tostring(parsed.sensor_id), de_muted=tobool(parsed.muted), de_rule_muted=tobool(parsed.muted_rule), de_rule_uuid=tostring(parsed.rule_uuid), de_mute_comment=tostring(parsed.muted_comment), de_muted_by=tostring(parsed.muted_user_uuid), de_date_muted=tostring(parsed.muted_timestamp), de_resolved_by=tostring(parsed.resolution_user_uuid), de_date_resolved=tostring(parsed.resolution_timestamp), de_resolution=tostring(parsed.resolution), de_resolution_comment=tostring(parsed.resolution_comment), de_first_seen=tostring(parsed.first_seen), de_last_seen=tostring(parsed.last_seen), de_created=todatetime(coalesce(parsed.created, TimeGenerated)), de_updated=tostring(parsed.updated), de_uuid=tostring(parsed.uuid), de_status=tostring(parsed.status), de_indicators=tostring(parsed.indicators), de_username=tostring(parsed.username), de_hostname=tostring(parsed.hostname), de_category=tostring(parsed.rule_category), de_event_count=todouble(parsed.event_count), de_events=tostring(parsed.events), de_primary_attack_id=tostring(parsed.rule_primary_attack_id), de_secondary_attack_id=tostring(parsed.rule_secondary_attack_id), de_rule_url=tostring(parsed.rule_url), Type="FncEventsDetections_CL" | project TimeGenerated, de_device_ip, de_event_count, de_events, de_indicators, de_last_seen, de_status, de_rule_name, de_severity, de_confidence, de_resolved_by, de_resolution, de_resolution_comment, de_date_resolved, de_rule_uuid, de_category, de_created, de_updated, de_first_seen, de_muted, de_rule_muted, de_mute_comment, de_muted_by, de_date_muted, de_sensor_id, de_account_id, de_uuid, de_username, de_hostname, de_primary_attack_id, de_secondary_attack_id, de_rule_url, Type }; union isfuzzy=true FortiNDR_Cloud_suricata_view, FortiNDR_Cloud_observation_view, FortiNDR_Cloud_detections_view