Загрузка данных


        # Отправляем все задачи в пул. Пул сам ограничит параллелизм до $ThrottleLimit.
        $submitted = 0
        foreach ($task in $tasks) {
            $ps = [powershell]::Create()
            $ps.RunspacePool = $pool

            # Вызываем AddScript отдельно, без цепочки методов
            $null = $ps.AddScript({
                param($dc, $xpath, $max)
                try {
                    $evts = Get-WinEvent -ComputerName $dc -LogName 'Security' `
                                -FilterXPath $xpath -MaxEvents $max -ErrorAction Stop
                    $evts | ForEach-Object {
                        [PSCustomObject]@{
                            TargetUser = $_.Properties[5].Value
                            LogonType  = $_.Properties[8].Value
                            SourceHost = $_.Properties[18].Value
                        }
                    }
                } catch {
                    if ($_.FullyQualifiedErrorId -match 'NoMatchingEventsFound' -or
                        $_.Exception.Message        -match 'No events were found') {
                        return
                    }
                    [PSCustomObject]@{ Error = $_.Exception.Message }
                }
            })

            # Добавляем параметры по одному. Так парсер не будет путаться в переносах строк.
            $null = $ps.AddParameter('dc',    $task.DC)
            $null = $ps.AddParameter('xpath', $task.XPath)
            $null = $ps.AddParameter('max',   $MaxEventsPerDC)

            $handle = $ps.BeginInvoke()

            $jobs.Add([PSCustomObject]@{
                PS        = $ps
                Handle    = $handle
                Task      = $task
                StartTime = [DateTime]::UtcNow
                Stopped   = $false
            })
            $submitted++

            if ($submitted -le 5) {
                Write-ScanLog "    → $($task.Account) @ $($task.DC)"
            }
        }