Задание запуска Powershell, задание ожидания, поток хоста никогда не завершается при запуске из ASP.NET IIS

В настоящее время я пытаюсь создать сценарий очистки потока с помощью powershell, инициированного из IIS. Я создал потоковый процесс «Убить процесс по владельцу», используя удаленное взаимодействие 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 :)

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, я получаю сообщение от каждой машины. Как показывает использование моей оперативной памяти, все задания выполняются, но вывод не возвращается должным образом, и мой хост-поток просто сидит там... ждет...


person Daniel    schedule 07.07.2011    source источник


Ответы (3)


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

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 для чего-то еще в своем коде, но просто хотели убедиться, что другие люди увидят эту альтернативу.

person Don Jones    schedule 12.07.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;
}

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

person Daniel    schedule 08.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?

person Matt    schedule 07.07.2011
comment
Спасибо, попробую записаться - person Daniel; 08.07.2011
comment
Не очень хорошо :P Он регистрирует все это, когда я запускаю его из консоли, но запускаю его из IIS, и это дает мне это: - person Daniel; 08.07.2011
comment
********************* Старт стенограммы Windows PowerShell Время начала: 20110708093327 Имя пользователя: DOMAIN\DomainAdminUser Компьютер: IISHost (Microsoft Windows NT 6.1.7601 с пакетом обновления 1) * ********************* - person Daniel; 08.07.2011
comment
ничего больше? или это комментарии удаляют это...? Мне интересно помочь и узнать, как вы запускаете это из IIS, поэтому отправьте мне электронное письмо с журналом — thompsonson at gmail dot com - person Matt; 08.07.2011