# Отправляем все задачи в пул. Пул сам ограничит параллелизм до $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)"
}
}