<#
.SYNOPSIS
    DLP email outbound collector for AWatch-rus (Phase 2.5).
    Monitors outgoing email via Outlook COM Sent Items polling
    and/or SMTP network connection detection.

.DESCRIPTION
    Two collection modes (configurable, can run simultaneously):
      - outlook : Polls Outlook Sent Items via COM for new messages.
      - smtp    : Monitors SMTP connections (ports 25/587/465) via
                  Get-NetTCPConnection for any process sending mail.

    Sends heartbeats to AW bucket `aw-email-monitor_<host>`.
    Evaluates DLP policy rules from `endpoint.email[]` section.
    Supports enforcement: action="block" moves the email to Drafts
    (Outlook mode) or logs with enforced=false (SMTP mode).
#>
[CmdletBinding()]
param(
    [string]$ConfigPath = 'C:\ProgramData\AWatch-rus\deployment-config.json',
    [string]$ServerHost,
    [int]$ServerPort,
    [ValidateSet('http', 'https')]
    [string]$ServerScheme,
    [string]$PolicyPath,
    [string]$LogPath,
    [int]$PollSeconds,
    [ValidateSet('outlook', 'smtp', 'both')]
    [string]$Mode = 'smtp'
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

# ---------------------------------------------------------------------------
# Shared infrastructure (mirrors other collectors)
# ---------------------------------------------------------------------------

function Get-DeploymentConfig {
    param([string]$Path)
    if ($Path -and (Test-Path -LiteralPath $Path)) {
        return Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json
    }
    return $null
}

function Write-CollectorLog {
    param([string]$Message)
    if (-not $script:LocalAgentLogsEnabled) { return }
    try {
        Add-Content -LiteralPath $script:LogPath -Value ('{0} {1}' -f (Get-Date -Format s), $Message)
    }
    catch { }
}

function Invoke-AwJsonPost {
    param(
        [Parameter(Mandatory = $true)][string]$Uri,
        [Parameter(Mandatory = $true)][string]$Json
    )
    $bytes = [Text.Encoding]::UTF8.GetBytes($Json)
    Invoke-RestMethod -Method Post -Uri $Uri -ContentType 'application/json; charset=utf-8' -Body $bytes | Out-Null
}

function Ensure-Bucket {
    param(
        [string]$BucketId,
        [string]$ClientName,
        [string]$BucketType
    )
    if ($script:KnownBuckets.ContainsKey($BucketId)) { return }
    $body = @{
        client   = $ClientName
        type     = $BucketType
        hostname = $script:Hostname
    } | ConvertTo-Json -Compress
    Invoke-AwJsonPost -Uri "$($script:ApiBase)/buckets/$BucketId" -Json $body
    $script:KnownBuckets[$BucketId] = $true
}

function Get-StringHash {
    param([AllowNull()][string]$Value)
    if ($null -eq $Value) { return $null }
    $bytes = [Text.Encoding]::UTF8.GetBytes($Value)
    $sha = [Security.Cryptography.SHA256]::Create()
    try {
        ($sha.ComputeHash($bytes) | ForEach-Object { $_.ToString('x2') }) -join ''
    }
    finally { $sha.Dispose() }
}

function Send-EmailHeartbeat {
    param(
        [string]$SignalType,
        [hashtable]$Data
    )
    $bucketId = 'aw-email-monitor_' + $script:Hostname
    Ensure-Bucket -BucketId $bucketId -ClientName 'aw-email-monitor' -BucketType 'aw.dlp.email'
    $payload = @{
        timestamp = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
        duration  = 0
        data      = @{
            signalType = $SignalType
            username   = $env:USERNAME
            sessionId  = $script:SessionId
            hostname   = $script:Hostname
            source     = 'email-outbound-collector'
        } + $Data
    } | ConvertTo-Json -Depth 6 -Compress
    Invoke-AwJsonPost -Uri "$($script:ApiBase)/buckets/$bucketId/heartbeat?pulsetime=$script:PulseSeconds" -Json $payload
}

function Send-EmailIncidentHeartbeat {
    param(
        [string]$RuleId,
        [string]$Action,
        [string]$Severity,
        [string]$Message,
        [hashtable]$Data
    )
    $bucketId = 'aw-dlp-incidents_' + $script:Hostname
    Ensure-Bucket -BucketId $bucketId -ClientName 'aw-dlp-incidents' -BucketType 'aw.dlp.incident'
    $payload = @{
        timestamp = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
        duration  = 0
        data      = @{
            ruleId     = $RuleId
            action     = $Action
            severity   = $Severity
            message    = $Message
            signalType = 'email_outbound'
            username   = $env:USERNAME
            sessionId  = $script:SessionId
            hostname   = $script:Hostname
            source     = 'email-outbound-collector'
        } + $Data
    } | ConvertTo-Json -Depth 7 -Compress
    Invoke-AwJsonPost -Uri "$($script:ApiBase)/buckets/$bucketId/heartbeat?pulsetime=$script:PulseSeconds" -Json $payload
}

function Show-EnforcementNotification {
    param(
        [Parameter(Mandatory = $true)][string]$Title,
        [Parameter(Mandatory = $true)][string]$Body
    )
    try {
        Add-Type -AssemblyName System.Windows.Forms -ErrorAction SilentlyContinue
        $icon = New-Object System.Windows.Forms.NotifyIcon
        $icon.Icon = [System.Drawing.SystemIcons]::Warning
        $icon.BalloonTipTitle = $Title
        $icon.BalloonTipText = $Body
        $icon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Warning
        $icon.Visible = $true
        $icon.ShowBalloonTip(5000)
        Start-Sleep -Milliseconds 200
        $icon.Dispose()
    }
    catch { }
}

# ---------------------------------------------------------------------------
# DLP Policy
# ---------------------------------------------------------------------------

function Load-EmailPolicy {
    param([string]$Path)

    $script:Policy = [ordered]@{
        defaults = [ordered]@{
            enabled         = $true
            cooldownSeconds = 300
            action          = 'alert'
            severity        = 'medium'
        }
        endpoint = [ordered]@{
            email = @()
        }
    }

    if (-not $Path -or -not (Test-Path -LiteralPath $Path)) {
        Write-CollectorLog ("policy not found, using defaults: {0}" -f $Path)
        return
    }

    try {
        $raw = Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json
        if ($raw.defaults) {
            if ($raw.defaults.PSObject.Properties.Name -contains 'enabled') { $script:Policy.defaults.enabled = [bool]$raw.defaults.enabled }
            if ($raw.defaults.cooldownSeconds) { $script:Policy.defaults.cooldownSeconds = [int]$raw.defaults.cooldownSeconds }
            if ($raw.defaults.action) { $script:Policy.defaults.action = [string]$raw.defaults.action }
            if ($raw.defaults.severity) { $script:Policy.defaults.severity = [string]$raw.defaults.severity }
        }
        if ($raw.endpoint -and $raw.endpoint.email) {
            $script:Policy.endpoint.email = @($raw.endpoint.email)
        }
    }
    catch {
        Write-CollectorLog ("policy parse failed: {0}" -f $_.Exception.Message)
    }
}

function Should-EmitByCooldown {
    param(
        [string]$Fingerprint,
        [int]$CooldownSeconds
    )
    $now = (Get-Date).ToUniversalTime()
    if ($script:Cooldown.ContainsKey($Fingerprint)) {
        $last = [datetime]$script:Cooldown[$Fingerprint]
        if ((New-TimeSpan -Start $last -End $now).TotalSeconds -lt $CooldownSeconds) {
            return $false
        }
    }
    $script:Cooldown[$Fingerprint] = $now
    return $true
}

# ---------------------------------------------------------------------------
# Email DLP rule evaluation
# ---------------------------------------------------------------------------

function Evaluate-EmailRules {
    param(
        [string]$Subject,
        [string]$RecipientsJoined,
        [string]$SenderAddress,
        [int]$AttachmentCount,
        [string]$AttachmentNames,
        [int]$BodyLength,
        [string]$MessageId,
        $OutlookMailItem
    )

    foreach ($rule in @($script:Policy.endpoint.email)) {
        if (-not $rule) { continue }
        if ($rule.PSObject.Properties.Name -contains 'enabled' -and -not [bool]$rule.enabled) { continue }
        $ruleId = [string]$rule.id
        if (-not $ruleId) { continue }

        $matched = $true

        if ($rule.subjectRegex) {
            $matched = $matched -and ($Subject -match [string]$rule.subjectRegex)
        }
        if ($rule.recipientRegex) {
            $matched = $matched -and ($RecipientsJoined -match [string]$rule.recipientRegex)
        }
        if ($rule.senderRegex) {
            $matched = $matched -and ($SenderAddress -match [string]$rule.senderRegex)
        }
        if ($rule.attachmentRegex -and $AttachmentNames) {
            $matched = $matched -and ($AttachmentNames -match [string]$rule.attachmentRegex)
        }
        if ($rule.minAttachments) {
            $matched = $matched -and ($AttachmentCount -ge [int]$rule.minAttachments)
        }
        if ($rule.minBodyLength) {
            $matched = $matched -and ($BodyLength -ge [int]$rule.minBodyLength)
        }
        if ($rule.externalOnly -and [bool]$rule.externalOnly) {
            $internalDomain = if ($rule.internalDomain) { [string]$rule.internalDomain } else { '' }
            if ($internalDomain -and $RecipientsJoined -notmatch [regex]::Escape($internalDomain)) {
                # all recipients are external — continue matching
            }
            elseif ($internalDomain) {
                $matched = $false
            }
        }

        if (-not $matched) { continue }

        $cooldown = if ($rule.cooldownSeconds) { [int]$rule.cooldownSeconds } else { [int]$script:Policy.defaults.cooldownSeconds }
        $fingerprint = "email|$ruleId|$MessageId|$env:USERNAME"
        if (-not (Should-EmitByCooldown -Fingerprint $fingerprint -CooldownSeconds ([Math]::Max($cooldown, 30)))) { continue }

        $action = if ($rule.action) { [string]$rule.action } else { [string]$script:Policy.defaults.action }
        $severity = if ($rule.severity) { [string]$rule.severity } else { [string]$script:Policy.defaults.severity }
        $message = if ($rule.message) { [string]$rule.message } else { "Email rule matched: $ruleId" }

        $enforced = $false
        if ($action -eq 'block' -and $null -ne $OutlookMailItem) {
            $enforced = Invoke-EmailEnforcement -MailItem $OutlookMailItem -RuleId $ruleId
            Show-EnforcementNotification -Title 'DLP: письмо перемещено в черновики' -Body $message
        }
        elseif ($action -eq 'block') {
            Show-EnforcementNotification -Title 'DLP: обнаружена отправка письма' -Body $message
        }

        Send-EmailIncidentHeartbeat -RuleId $ruleId -Action $action -Severity $severity -Message $message -Data @{
            subject         = (Get-StringHash -Value $Subject)
            recipients      = (Get-StringHash -Value $RecipientsJoined)
            sender          = $SenderAddress
            attachmentCount = $AttachmentCount
            attachmentNames = $AttachmentNames
            bodyLength      = $BodyLength
            enforced        = $enforced
        }
        Write-CollectorLog ("incident email rule={0} action={1} severity={2} enforced={3} subject_hash={4}" -f $ruleId, $action, $severity, $enforced, (Get-StringHash -Value $Subject))
    }
}

function Invoke-EmailEnforcement {
    [OutputType([bool])]
    param(
        [Parameter(Mandatory = $true)]$MailItem,
        [string]$RuleId
    )
    try {
        $draftsFolder = $script:OutlookNamespace.GetDefaultFolder(16) # olFolderDrafts
        $MailItem.Move($draftsFolder) | Out-Null
        Write-CollectorLog ("enforcement: email moved to Drafts rule={0} subject_hash={1}" -f $RuleId, (Get-StringHash -Value $MailItem.Subject))
        return $true
    }
    catch {
        Write-CollectorLog ("enforcement: email move to Drafts failed rule={0}: {1}" -f $RuleId, $_.Exception.Message)
        return $false
    }
}

# ---------------------------------------------------------------------------
# Outlook Sent Items polling
# ---------------------------------------------------------------------------

function Initialize-OutlookCom {
    if ($script:OutlookDisabled) {
        return $false
    }

    if (-not (Test-OutlookProfileConfigured)) {
        Write-CollectorLog "Outlook profile not configured for current user, Outlook mode disabled"
        $script:OutlookDisabled = $true
        return $false
    }

    if (-not (Get-Process -Name OUTLOOK -ErrorAction SilentlyContinue | Select-Object -First 1)) {
        Write-CollectorLog "Outlook process not running, skipping COM initialization"
        return $false
    }

    try {
        $script:OutlookApp = [Runtime.InteropServices.Marshal]::GetActiveObject('Outlook.Application')
        $script:OutlookNamespace = $script:OutlookApp.GetNamespace('MAPI')
        $script:SentFolder = $script:OutlookNamespace.GetDefaultFolder(5) # olFolderSentMail
        Write-CollectorLog "Outlook COM initialized, Sent Items folder opened"
        return $true
    }
    catch {
        Write-CollectorLog ("Outlook COM init failed: {0}" -f $_.Exception.Message)
        return $false
    }
}

function Test-OutlookProfileConfigured {
    [OutputType([bool])]
    $officeRoots = @(
        'HKCU:\Software\Microsoft\Office',
        'HKCU:\Software\WOW6432Node\Microsoft\Office'
    )

    foreach ($root in $officeRoots) {
        if (-not (Test-Path -LiteralPath $root)) { continue }
        $versions = Get-ChildItem -LiteralPath $root -ErrorAction SilentlyContinue |
            Where-Object { $_.PSChildName -match '^\d+\.\d+$' } |
            Sort-Object { [version]$_.PSChildName } -Descending
        foreach ($ver in $versions) {
            $profilesPath = Join-Path $ver.PSPath 'Outlook\Profiles'
            if (Test-Path -LiteralPath $profilesPath) {
                $profiles = Get-ChildItem -LiteralPath $profilesPath -ErrorAction SilentlyContinue
                if ($profiles -and $profiles.Count -gt 0) {
                    return $true
                }
            }
        }
    }

    return $false
}

function Get-OutlookSentItems {
    param([datetime]$Since)

    $results = @()
    try {
        $items = $script:SentFolder.Items
        $items.Sort('[SentOn]', $true)

        $filter = "[SentOn] >= '{0}'" -f $Since.ToString('MM/dd/yyyy HH:mm')
        $restricted = $items.Restrict($filter)

        foreach ($item in $restricted) {
            try {
                if ($item.Class -ne 43) { continue } # olMail = 43

                $recipients = @()
                for ($i = 1; $i -le $item.Recipients.Count; $i++) {
                    $recip = $item.Recipients.Item($i)
                    $recipients += [string]$recip.Address
                }

                $attachmentNames = @()
                for ($i = 1; $i -le $item.Attachments.Count; $i++) {
                    $attachmentNames += [string]$item.Attachments.Item($i).FileName
                }

                $results += [pscustomobject]@{
                    EntryID        = [string]$item.EntryID
                    Subject        = [string]$item.Subject
                    SenderAddress  = [string]$item.SenderEmailAddress
                    SenderName     = [string]$item.SenderName
                    Recipients     = $recipients
                    RecipientsJoined = ($recipients -join '; ')
                    AttachmentCount = [int]$item.Attachments.Count
                    AttachmentNames = ($attachmentNames -join '; ')
                    BodyLength     = if ($item.Body) { $item.Body.Length } else { 0 }
                    SentOn         = $item.SentOn
                    MailItem       = $item
                }
            }
            catch { }
        }
    }
    catch {
        Write-CollectorLog ("Outlook Sent Items scan failed: {0}" -f $_.Exception.Message)
    }
    return $results
}

function Poll-OutlookSentItems {
    $items = Get-OutlookSentItems -Since $script:OutlookLastPoll

    foreach ($item in $items) {
        $entryId = $item.EntryID
        if ($script:SeenEntryIds.ContainsKey($entryId)) { continue }
        $script:SeenEntryIds[$entryId] = (Get-Date).ToUniversalTime()

        $subjectHash = Get-StringHash -Value $item.Subject

        Send-EmailHeartbeat -SignalType 'email_sent' -Data @{
            subject         = $subjectHash
            sender          = [string]$item.SenderAddress
            senderName      = [string]$item.SenderName
            recipientCount  = $item.Recipients.Count
            recipients      = (Get-StringHash -Value $item.RecipientsJoined)
            attachmentCount = [int]$item.AttachmentCount
            attachmentNames = [string]$item.AttachmentNames
            bodyLength      = [int]$item.BodyLength
            sentOn          = if ($item.SentOn) { $item.SentOn.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ') } else { '' }
            collectionMode  = 'outlook'
        }
        Write-CollectorLog ("email_sent outlook subject_hash={0} to={1} attachments={2}" -f $subjectHash, $item.Recipients.Count, $item.AttachmentCount)

        Evaluate-EmailRules `
            -Subject $item.Subject `
            -RecipientsJoined $item.RecipientsJoined `
            -SenderAddress $item.SenderAddress `
            -AttachmentCount $item.AttachmentCount `
            -AttachmentNames $item.AttachmentNames `
            -BodyLength $item.BodyLength `
            -MessageId $entryId `
            -OutlookMailItem $item.MailItem
    }

    $script:OutlookLastPoll = (Get-Date).AddSeconds(-10)

    # Cleanup old entry IDs (keep last 24h)
    $cleanupBefore = (Get-Date).ToUniversalTime().AddHours(-24)
    foreach ($k in @($script:SeenEntryIds.Keys)) {
        if ([datetime]$script:SeenEntryIds[$k] -lt $cleanupBefore) {
            $script:SeenEntryIds.Remove($k)
        }
    }
}

# ---------------------------------------------------------------------------
# SMTP network connection monitoring
# ---------------------------------------------------------------------------

function Poll-SmtpConnections {
    try {
        $smtpPorts = @(25, 587, 465, 2525)
        $connections = Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
            Where-Object { $smtpPorts -contains $_.RemotePort }

        foreach ($conn in @($connections)) {
            $processId = [int]$conn.OwningProcess
            $remoteAddr = [string]$conn.RemoteAddress
            $remotePort = [int]$conn.RemotePort
            $fingerprint = "{0}:{1}:{2}" -f $processId, $remoteAddr, $remotePort
            if ($script:SeenSmtpConnections.ContainsKey($fingerprint)) { continue }
            $script:SeenSmtpConnections[$fingerprint] = (Get-Date).ToUniversalTime()

            $processName = ''
            try {
                $proc = Get-Process -Id $processId -ErrorAction SilentlyContinue
                $processName = [string]$proc.ProcessName
            }
            catch { }

            Send-EmailHeartbeat -SignalType 'smtp_connection' -Data @{
                remoteAddress = $remoteAddr
                remotePort    = $remotePort
                processId     = $processId
                processName   = $processName
                localPort     = [int]$conn.LocalPort
                collectionMode = 'smtp'
            }
            Write-CollectorLog ("smtp_connection process={0}({1}) remote={2}:{3}" -f $processName, $processId, $remoteAddr, $remotePort)

            Evaluate-EmailRules `
                -Subject '' `
                -RecipientsJoined $remoteAddr `
                -SenderAddress $env:USERNAME `
                -AttachmentCount 0 `
                -AttachmentNames '' `
                -BodyLength 0 `
                -MessageId $fingerprint `
                -OutlookMailItem $null
        }

        # Cleanup old SMTP connections (keep last 8h)
        $cleanupBefore = (Get-Date).ToUniversalTime().AddHours(-8)
        foreach ($k in @($script:SeenSmtpConnections.Keys)) {
            if ([datetime]$script:SeenSmtpConnections[$k] -lt $cleanupBefore) {
                $script:SeenSmtpConnections.Remove($k)
            }
        }
    }
    catch {
        Write-CollectorLog ("SMTP poll error: {0}" -f $_.Exception.Message)
    }
}

# ---------------------------------------------------------------------------
# Initialization
# ---------------------------------------------------------------------------

$deploymentConfig = Get-DeploymentConfig -Path $ConfigPath
$resolvedServerHost = if ($ServerHost) { $ServerHost } elseif ($deploymentConfig) { [string]$deploymentConfig.server.host } else { throw 'ServerHost is required.' }
$resolvedServerPort = if ($PSBoundParameters.ContainsKey('ServerPort')) { $ServerPort } elseif ($deploymentConfig) { [int]$deploymentConfig.server.port } else { 5600 }
$resolvedServerScheme = if ($ServerScheme) { $ServerScheme } elseif ($deploymentConfig) { [string]$deploymentConfig.server.scheme } else { 'http' }
$resolvedPolicyPath = if ($PolicyPath) { $PolicyPath } elseif ($deploymentConfig -and $deploymentConfig.paths.PSObject.Properties.Name -contains 'policyPath') { [string]$deploymentConfig.paths.policyPath } else { 'C:\ProgramData\AWatch-rus\dlp-policy.json' }
$resolvedPollSeconds = if ($PSBoundParameters.ContainsKey('PollSeconds')) { $PollSeconds } elseif ($deploymentConfig) { [int]$deploymentConfig.collector.pollSeconds } else { 10 }
$resolvedLogsRoot = if ($deploymentConfig) { [string]$deploymentConfig.paths.logsRoot } else { 'C:\ProgramData\AWatch-rus\logs' }
$resolvedLogPath = if ($LogPath) { $LogPath } else { Join-Path $resolvedLogsRoot ("email-outbound-{0}.log" -f $env:USERNAME) }
$resolvedLocalAgentLogsEnabled = if ($deploymentConfig -and $deploymentConfig.PSObject.Properties.Name -contains 'logging' -and $deploymentConfig.logging.PSObject.Properties.Name -contains 'localAgentLogsEnabled') { [bool]$deploymentConfig.logging.localAgentLogsEnabled } else { $true }

if ($resolvedLocalAgentLogsEnabled -and -not (Test-Path -LiteralPath $resolvedLogsRoot)) {
    New-Item -Path $resolvedLogsRoot -ItemType Directory -Force | Out-Null
}

$script:ApiBase = '{0}://{1}:{2}/api/0' -f $resolvedServerScheme, $resolvedServerHost, $resolvedServerPort
$script:Hostname = $env:COMPUTERNAME
$script:SessionId = (Get-Process -Id $PID).SessionId
$script:KnownBuckets = @{}
$script:Cooldown = @{}
$script:SeenEntryIds = @{}
$script:SeenSmtpConnections = @{}
$script:PulseSeconds = [Math]::Max($resolvedPollSeconds * 3, 30)
$script:LocalAgentLogsEnabled = $resolvedLocalAgentLogsEnabled
$script:LogPath = $resolvedLogPath
$script:OutlookApp = $null
$script:OutlookNamespace = $null
$script:SentFolder = $null
$script:OutlookLastPoll = (Get-Date).AddMinutes(-5)
$script:OutlookDisabled = $false

Load-EmailPolicy -Path $resolvedPolicyPath
Write-CollectorLog ("email collector started mode={0} against {1}" -f $Mode, $script:ApiBase)

$useOutlook = ($Mode -eq 'outlook' -or $Mode -eq 'both')
$useSmtp = ($Mode -eq 'smtp' -or $Mode -eq 'both')
$outlookReady = $false

if ($useOutlook) {
    $outlookReady = Initialize-OutlookCom
    if (-not $outlookReady -and $Mode -eq 'outlook') {
        Write-CollectorLog "Outlook COM not available, collector will retry"
    }
}

# ---------------------------------------------------------------------------
# Main loop
# ---------------------------------------------------------------------------

while ($true) {
    try {
        if (-not $script:Policy.defaults.enabled) {
            Start-Sleep -Seconds $resolvedPollSeconds
            continue
        }

        if ($useOutlook) {
            if (-not $outlookReady) {
                $outlookReady = Initialize-OutlookCom
            }
            if ($outlookReady) {
                try {
                    Poll-OutlookSentItems
                }
                catch {
                    Write-CollectorLog ("outlook poll error: {0}" -f $_.Exception.Message)
                    $outlookReady = $false
                    $script:OutlookApp = $null
                    $script:OutlookNamespace = $null
                    $script:SentFolder = $null
                }
            }
        }

        if ($useSmtp) {
            try {
                Poll-SmtpConnections
            }
            catch {
                Write-CollectorLog ("smtp poll error: {0}" -f $_.Exception.Message)
            }
        }
    }
    catch {
        Write-CollectorLog ("collector error: {0}" -f $_.Exception.Message)
    }

    Start-Sleep -Seconds $resolvedPollSeconds
}
