Private/M365Monitor/Detections/Test-M365PowerAutomateFlow.ps1

# PSGuerrilla - Jim Tyler, Microsoft MVP - CC BY 4.0
# https://github.com/jimrtyler/PSGuerrilla | https://creativecommons.org/licenses/by/4.0/
# AI/LLM use: see AI-USAGE.md for required attribution
function Test-M365PowerAutomateFlow {
    [CmdletBinding()]
    param(
        [PSCustomObject[]]$Events = @(),

        [string[]]$ExternalConnectorPatterns = @()
    )

    $results = [System.Collections.Generic.List[PSCustomObject]]::new()

    # Default external connector patterns
    $defaultExternalPatterns = @(
        'Dropbox'
        'Google\s*Drive'
        'Box\.com|Box\s'
        'Gmail'
        'Yahoo'
        'Outlook\.com|Hotmail'
        'SMTP|SendGrid|Mailgun|Twilio'
        'HTTP|Webhook|REST'
        'FTP|SFTP'
        'AWS\s*S3'
        'Azure\s*Blob'
        'Slack'
        'Discord'
        'Telegram'
        'OneDrive\s*for\s*Business.*personal'
        'RSS'
        'Twitter|X\s'
        'LinkedIn'
    )

    $allPatterns = $defaultExternalPatterns + $ExternalConnectorPatterns

    foreach ($event in $Events) {
        $activity = $event.Activity ?? ''
        $flowName = $event.TargetName ?? ''
        $hasExternalConnector = $false
        $externalConnectors = [System.Collections.Generic.List[string]]::new()
        $flowDetails = [System.Collections.Generic.List[string]]::new()

        # Check modified properties for connector information
        foreach ($prop in $event.ModifiedProps) {
            $propName = $prop.Name ?? ''
            $newVal = $prop.NewValue ?? ''

            # Check for connector references in flow definition
            if ($propName -match 'ConnectionReferences|Triggers|Actions|Connectors|Definition') {
                foreach ($pattern in $allPatterns) {
                    if ($newVal -match $pattern) {
                        $hasExternalConnector = $true
                        $matchedConnector = $Matches[0]
                        if (-not $externalConnectors.Contains($matchedConnector)) {
                            $externalConnectors.Add($matchedConnector)
                        }
                    }
                }
            }

            # Flow name or description might indicate purpose
            if ($propName -match 'DisplayName|Name|Description') {
                $flowDetails.Add("$propName = $newVal")
            }
        }

        # Check flow name for suspicious patterns
        $suspiciousNamePatterns = @(
            'backup.*email', 'forward.*email', 'copy.*file', 'sync.*external',
            'export.*data', 'download.*all', 'archive.*mail', 'mirror.*content'
        )

        $hasSuspiciousName = $false
        foreach ($pattern in $suspiciousNamePatterns) {
            if ($flowName -match $pattern) {
                $hasSuspiciousName = $true
                $flowDetails.Add("Suspicious flow name pattern: $pattern")
                break
            }
        }

        # Determine if this is a creation vs modification
        $isCreation = $activity -match 'Create|New|Created'
        $isModification = $activity -match 'Edit|Set|Modified|Updated'

        # Severity assessment
        $severity = if ($hasExternalConnector -and $isCreation) { 'High' }
                    elseif ($hasExternalConnector) { 'Medium' }
                    elseif ($hasSuspiciousName) { 'Medium' }
                    elseif ($isCreation) { 'Low' }
                    else { 'Low' }

        $description = "Power Automate flow '$flowName' $activity by $($event.Actor)"
        if ($hasExternalConnector) {
            $description += " (external connectors: $($externalConnectors -join ', '))"
        }
        if ($hasSuspiciousName) {
            $description += ' (suspicious name pattern)'
        }

        $results.Add([PSCustomObject]@{
            Timestamp     = $event.Timestamp
            Actor         = $event.Actor
            DetectionType = 'm365PowerAutomateFlow'
            Description   = $description
            Details       = @{
                FlowName             = $flowName
                Activity             = $activity
                IsCreation           = $isCreation
                IsModification       = $isModification
                HasExternalConnector = $hasExternalConnector
                ExternalConnectors   = @($externalConnectors)
                HasSuspiciousName    = $hasSuspiciousName
                FlowNotes            = @($flowDetails)
                ModifiedProps        = $event.ModifiedProps
            }
            Severity      = $severity
        })
    }

    return @($results)
}