@genbachae

Как работать с Start-Job в Power Shell?

В написанном скрипте:
[xml]$inputs = New-Object system.Xml.XmlDocument
$inputs.Load('.\inputs.xml') 

[string]$result = ''
[string]$adresses = ''

foreach ($server in $inputs.SelectNodes('//server'))
{
	$hostname = $server.host                                    #   получаем DNS имя сервера
    Start-Job {                                                 #   стартуем задание
	    if (Test-Connection $hostname -Quiet)
	    {
		    $result += "Ping to " + $hostname + " success`r`n"      #   формируем содержимое файла report.txt
		    $port = $server.port
		    $sock = new-object System.Net.Sockets.Socket -ArgumentList $([System.Net.Sockets.AddressFamily]::InterNetwork),$([System.Net.Sockets.SocketType]::Stream),$([System.Net.Sockets.ProtocolType]::Tcp)
			    try {
				    $sock.Connect($hostname,$Port) | Out-Null       #   попытка соединения
				    $result += "port " + $port + " connect success`r`n"
				    $result += "`r`n"
				    $sock.Close()
				    }
			    catch {
			    $result += "port " + $port + " connect fail`r`n"
			    $result += "`r`n"
			    } 
		
	    }
	    else
	    {
		    $result += "Ping to " + $hostname + " fail`r`n"         #   формируем содержимое файла report.txt
	    }
    }                                                           #   конец задания
}
$result += "`r`n"

foreach ($process in $inputs.SelectNodes('//process'))          #   определяет какие процессы запущены
{
	if (Get-Process -Name $process.InnerText -ErrorAction SilentlyContinue)
	{
		$result += "Process " + $process.InnerText + " exists`r`n"
	}
	else
	{
		$result += "Process " + $process.InnerText + " not exists`r`n"
	}
}
$result += "`r`n"

foreach ($service in $inputs.SelectNodes('//service'))
{
	if (Get-service -Name $service.InnerText -ErrorAction SilentlyContinue)
	{  # 
		$Servicestatus = Get-service $service.InnerText | select status, DisplayName      # получение списка служб в Powershell
		$result += "Service " + $service.InnerText + " " + $Servicestatus.status + "`r`n"
	}
	else
	{
		$result += "Service " + $service.InnerText + " " + "not exists`r`n"
	}
	
}

Start-Sleep -Sec 99                                                 #   задержка чтобы пинги отработали

Out-File -FilePath .\report.txt -InputObject $result -Encoding Default
foreach ($adress in $inputs.SelectNodes('//email'))
{
	$adresses += $adress.InnerText + "; "
}
if ($adresses -ne '')
{
	Add-Type -AssemblyName Microsoft.Office.Interop.Outlook         #   ошибка если нет Outlook на компе
	$Outlook = New-Object -ComObject Outlook.Application
	$Mail = $Outlook.CreateItem(0)
	
	$Mail.To = $adresses
	$Computer = Get-WmiObject  -Class win32_ComputerSystem
	
	$Mail.Subject = "Testing report on "+ $Computer.Name
	$Mail.Body =$result
	$Mail.Send()
}

предполагается что в первом цикле foreach будут пинговаться хосты и результаты этих пингов будут заноситься в переменную $result, но этого не происходит. Весь остальной код отрабатывает без проблемм!

Вопрос: подскажите что я в первом цикле foreach делаю не так?
  • Вопрос задан
  • 586 просмотров
Решения вопроса 1
@genbachae Автор вопроса
Удалось решить следующим образом:
[xml]$inputs = New-Object system.Xml.XmlDocument
$inputs.Load('.\inputs.xml') 

[string]$result = ''
[string]$adresses = ''
$matrix = New-Object System.Collections.ArrayList

$Get_Ping={                                                      #   функция будет выполняться в задании
    param($server)
    $hostname = $server.host

    if (Test-Connection $hostname -Quiet -count 1){
        $resPing += "Ping to " + $hostname + " success`r`n"      #   формируем содержимое файла report.txt
        $port = $server.port
        $sock = new-object System.Net.Sockets.Socket -ArgumentList ( 
                    $([System.Net.Sockets.AddressFamily]::InterNetwork),
                    $([System.Net.Sockets.SocketType]::Stream),
                    $([System.Net.Sockets.ProtocolType]::Tcp) )
        try {
            $sock.Connect($hostname,$Port) | Out-Null            #   попытка соединения
            $resPing += "Port " + $port + " connect success`r`n`r`n"
            $sock.Close()
        }
        catch {
            $resPing += "Port " + $port + " connect fail`r`n`r`n"
        } 
    }
    else {
        $resPing += "Ping to " + $hostname + " fail`r`n"         #   формируем содержимое файла report.txt
    }
    return $resPing
}

foreach ($server in $inputs.SelectNodes('//server'))
{
    $jb = Start-Job $Get_Ping -Args $server                      #   запускаем задание для каждого хоста
	$matrix.Add($jb)
}

foreach ($process in $inputs.SelectNodes('//process'))           #   определяет какие процессы запущены
{
	if (Get-Process -Name $process.InnerText -ErrorAction SilentlyContinue)
	{
		$result += "Process " + $process.InnerText + " exists`r`n"
	}
	else
	{
		$result += "Process " + $process.InnerText + " not exists`r`n"
	}
}
$result += "`r`n"

foreach ($service in $inputs.SelectNodes('//service'))
{
	if (Get-service -Name $service.InnerText -ErrorAction SilentlyContinue)
	{  # 
		$Servicestatus = Get-service $service.InnerText | select status, DisplayName      # получение списка служб в Powershell
		$result += "Service " + $service.InnerText + " " + $Servicestatus.status + "`r`n"
	}
	else
	{
		$result += "Service " + $service.InnerText + " " + "not exists`r`n"
	}
	
}
$result += "`r`n"

foreach($jb in $matrix)                                          #   собираем результаты выполнения пингов
{
    $rez = $jb|Wait-Job|Receive-Job
    $result += $rez
}

Out-File -FilePath .\report.txt -InputObject $result -Encoding Default
foreach ($adress in $inputs.SelectNodes('//email'))
{
	$adresses += $adress.InnerText + "; "
}
if ($adresses -ne '')
{
	Add-Type -AssemblyName Microsoft.Office.Interop.Outlook
	$Outlook = New-Object -ComObject Outlook.Application
	$Mail = $Outlook.CreateItem(0)
	
	$Mail.To = $adresses
	$Computer = Get-WmiObject  -Class win32_ComputerSystem
	
	$Mail.Subject = "Testing report on "+ $Computer.Name
	$Mail.Body =$result
	$Mail.Send()
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@NortheR73
системный инженер
Вот тут, похоже, Ваш случай описан...
Ответ написан
Комментировать
@MaxKozlov Куратор тега PowerShell
во-первых, нигде нет Wait-Job
во-вторых, сама Job не может ничего писать в result, необходимо просто выдавать всё в output
в-третьих, внутри скрипта джоба нельзя использовать внешние переменные - они там недоступны, надо всё передавать через аргументы или $using:
в-четвёртых, то что выдаётся в output, после wait-job нужно получать через receive-job
в-пятых, почту лучше отправлять через Send-MailMessage
наконец, в-шестых, вместо Job, лучше использовать ThreadJob или PoshRSJob - они меньше нагружают комп

то есть схема примерно такая:
$sourcedata = get-content in_file
$jobs = 
foreach ($data in $sourcedata) {
   Start-Job { somescript $using:data }
}
$result = $jobs | wait-Job | receive-Job
$jobs | remove-Job
$result | set-content out_file
send-mailmessage ...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы