2017-01-17 4 views
0

Предположим, у меня есть массив имен хостов Windows:Параллельный поиск пользовательских сеансов с нескольких серверов Windows, в PowerShell

$server_hostnames = @("server1","server2") 

Для каждого сервера мне нужно найти, если есть какие-сессии для конкретного пользователя, а затем в идеале захватить все сеансы в новом массиве.

$results = @() 
$account = "JohnDoe" 
foreach ($s in $server_hostnames) { 
    $r = (qwinsta /server:$($s) 2> $null | out-string -stream | sls $account) 
    $results += $r 
} 

В этом примере у меня есть 2 сервера, но в производство я бы запустить его против 2-3000 серверов, поэтому параллельное выполнение является чрезвычайно важным.

Я сделал несколько попыток переписать код с использованием заданий, рабочих процессов или Split-Pipeline, но с небольшим успехом. Обычно фильтрация с sls (Select-String) не работает, даже с findstr.

Split-Pipeline пример:

PS C:\SplitPipeline> $server_hostnames | Split-Pipeline {process{ $_; qwinsta /server:$($_) | out-string -stream | sls $account }} 
Split-Pipeline : Cannot bind argument to parameter 'Pattern' because it is null. 
At line:1 char:21 
+ $server_hostnames | Split-Pipeline {process{ $_; qwinsta /server:$($_) | out-str ... 
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    + CategoryInfo   : InvalidData: (:) [Split-Pipeline], ParameterBindingValidationException 
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,SplitPipeline.SplitPipelineCommand
+0

Похоже, что учетная запись $ имеет пустую стоимость. Откуда вы его назначаете? –

+0

Это не нуль, в моем примере вы можете увидеть, что $ account = "JohnDoe" – PowerShellEnthusiast

+0

Вы видите, что вы получаете, когда выполняете это: $ server_hostnames | Split-Pipeline {process {$ _; qwinsta/server: $ ($ _) | out-string -stream}} –

ответ

0

Использование рабочих мест вы могли бы сделать что-то вроде этого:

$servers = 'server1', 'server2' 
$account = 'JohnDoe' 
$results = @() 

$sb = { 
    Param($server, $name) 
    & qwinsta /server:$server | 
    Select-String $name -SimpleMatch | 
    Select-Object -Expand Line 
} 

$servers | ForEach-Object { 
    Start-Job -ScriptBlock $sb -ArgumentList $_, $account | Out-Null 
} 

$results += while (Get-Job -State Running) { 
    Get-Job -State Complete | ForEach-Object { 
    Receive-Job -Job $_ 
    Remove-Job -Job $_ 
    } 
} 

$results += Get-Job -State Complete | ForEach-Object { 
    Receive-Job -Job $_ 
    Remove-Job -Job $_ 
} 

Однако, так как вы хотите запустить qwinsta против нескольких тысяч серверов, вы, вероятно, хотите использовать job queue, а не одновременно выполнять все задания, в противном случае огромное количество заданий может исчерпать ресурсы вашего локального компьютера.

+0

Еще раз спасибо Ансгар, это красивый код; Я также тестировал эту версию, и, как вы предсказали, она исчерпывает все ресурсы; Я постараюсь переписать его в очередь! – PowerShellEnthusiast

+0

В последние несколько дней я немного занят, но я успешно переписал сценарий для использования очереди (я добавил его к исходному вопросу). Физические ресурсы локального компьютера остаются узким местом, я установил максимальное количество одновременных заданий 75. Есть еще одна вещь, о которой мне нужно заботиться ... каждый результат работы (каждая строка) также должен содержать имя сервера, в противном случае вывод не является полностью полезным. – PowerShellEnthusiast

+0

Пожалуйста, не редактируйте ответы в своем вопросе. Вы можете публиковать ответ самостоятельно.Что касается включения имени хоста в выходной файл, вы можете, например, использовать echo '$ server' или' $ env: COMPUTERNAME' в скриптовом блоке job. –

Смежные вопросы