Задание запуска Powershell, ожидание, поток хоста никогда не завершается при запуске из ASP.NET IIS - PullRequest
5 голосов
/ 07 июля 2011

В настоящее время я пытаюсь создать многопоточный сценарий очистки с powershell, инициированный из IIS.Я создал многопоточный «Kill process by owner», используя удаленное взаимодействие powershell, запущенный из того же списка серверов, что и мой сценарий очистки, и это не проблема.

$jobs = @()
foreach ($comp in $comps) {
    $jobs += start-job -FilePath ("CleanupJob.ps1") -ArgumentList $comp, $username
    Write-Host "Started Job on: $comp"
}
foreach($job in $jobs)
{
    $job | wait-job | out-null
    receive-job $job.ID
}

Remove-Job -State Completed 

Когда я запускаю свой сценарий из powershellКонсоль, все работает отлично, основной поток запускает 28 новых процессов, которые запускают удаленное подключение к каждому серверу и ждут завершения всех заданий.Когда они закончены, я получаю свой вывод, и поток хоста существует.Все работает как запланировано.

Не так, когда я запускаю его из своего приложения asp.net, я получаю "" Запущено задание на: $ comp "" для каждого из моих 28 серверов, но только результат первого14, а затем хост-поток просто сидит там.(пока я не убью его огнем, и мой вывод вернется на веб-страницу asp.net)

У меня нет возможности увидеть, что происходит в скрипте, когда я запускаю его со страницы asp.net. Всевидно, что использование процессора / оперативной памяти падает до тех же уровней, что и при запуске из PSconsole, но мой основной поток никогда не закрывается.Так что я верю, что скрипт работает так, как предполагалось, но моя веб-страница зависает до тех пор, пока основной поток не закроется (чего он никогда не делает, как указано).


Так я называю свой скрипт (не симпатичный.net <3 powershell way:) </p>

public string RunProgramme(string scriptpath, string arguments)
{
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.FileName = @"powershell.exe";
    startInfo.Arguments = "& \'"+scriptpath+"\' "+ arguments;

    //return startInfo.Arguments;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardError = true;
    startInfo.UseShellExecute = false;
    startInfo.CreateNoWindow = true;
    Process process = new Process();
    process.StartInfo = startInfo;
    process.Start();

    string output = process.StandardOutput.ReadToEnd();
    string errors = process.StandardError.ReadToEnd();
    return output;
}

Загадка углубляется, добавьте эту строку в мои многопоточные задания

Invoke-Command -Session $session  -ScriptBlock {param($path) net send mymachine $path}  -Args $msg 

И когда я запускаю свой скрипт из IIS, я получаю сообщение откаждая машина.Как показывает мое использование оперативной памяти, все задания выполняются, но вывод не возвращается должным образом, и поток моего хоста просто сидит ... в ожидании ...

Ответы [ 3 ]

7 голосов
/ 12 июля 2011

Как примечание, у вас есть некоторые ненужные вещи, происходящие.

foreach ($comp in $comps) {
    start-job -FilePath ("CleanupJob.ps1") -ArgumentList $comp, $username
    Write-Verbose "Started Job on: $comp"
}
Get-Job | Wait-Job | Out-Null
Remove-Job -State Completed 

PowerShell уже создает список заданий; нет необходимости делать это в переменной $ jobs, и не нужно перечислять их, чтобы выполнить ожидание.

Конечно, вы можете использовать $ jobs для чего-то другого в вашем коде - но просто хотели убедиться, что другие люди увидят эту альтернативу.

3 голосов
/ 08 июля 2011

Я нашел решение. Это тупик, вызванный звонком

string output = process.StandardOutput.ReadToEnd();
string errors = process.StandardError.ReadToEnd();

Сразу после друг друга. Вместо этого я последовал http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandarderror.aspx#Y95 и сделал это вместо:

public string RunProgramme(string scriptpath, string arguments)
{
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.FileName = @"powershell.exe";
    startInfo.Arguments = "& \'"+scriptpath+"\' "+ arguments;
    startInfo.ErrorDialog = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardError = true;
    startInfo.UseShellExecute = false;
    startInfo.CreateNoWindow = true;
    Process process = new Process();
    process.StartInfo = startInfo;
    process.Start();
    process.BeginErrorReadLine(); 
    //Use BeginErrorReadLine on one of the streams to avoid the deadlock 
    //(i didnt need my error stream, but I did need to filter the errors from my output, so i did this)
    string output = process.StandardOutput.ReadToEnd();
    process.WaitForExit(1000 * 60);
    return output;
}

Больше не висит:)

0 голосов
/ 07 июля 2011

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

$logfile = "C:\Documents and Settings\username\My Documents\WindowsPowerShell\logs\$(Get-Date -uformat "%Y%m%d - %H%M%S").log"
Start-Transcript -Path $logfile

Мне интересно знать, как вы вызываете это также из ASP.Net?

...