2011-07-07 22 views
5

Obecnie próbuję zbudować skrypt czyszczenia wątków z powershell, inicjowany z IIS. Zrobiłem gwintowany proces "Kill by owner" przy użyciu PowerShot Remoting, uruchamiany z tej samej listy serwerów co mój skrypt czyszczący i to działa bez problemu.Powershell start-job, wait-job, wątek hosta nigdy nie kończy się po uruchomieniu z ASP.NET IIS

$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 

Kiedy uruchomić mój skrypt z konsoli PowerShell, cała rzecz działa doskonale, wątek główny rozpoczyna się 28 nowych procesów, które nawiązać połączenie usług zdalnych do każdego serwera i czeka na wszystkie zadania do końca. Po ich zakończeniu otrzymuję dane wyjściowe i istnieje wątek hosta. Wszystko działa zgodnie z planem.

Nie, jeśli uruchomię go z mojej aplikacji asp.net, otrzymuję "" Rozpoczęte zadanie na: $ comp "" dla każdego z moich 28 serwerów, ale tylko wynik z pierwszych 14, a następnie wątek hosta po prostu tam siedzi. (dopóki nie zabiję go ogniem, a moje dane wyjściowe zostaną zwrócone na stronę asp.net)

Nie mam sposobu sprawdzenia, co dzieje się w skrypcie po uruchomieniu go ze strony asp.net. Wszystko, co widzę jest spadek użycia cpu/ram na takie same poziomy jak w przypadku uruchomienia go z PSconsole, ale mój główny wątek nigdy się nie zamyka. Sądzę, że skrypt działa zgodnie z założeniami, ale moja strona internetowa zawiesza się, dopóki główny wątek nie zostanie zamknięty (co nigdy nie nastąpi, jak podano).


ten sposób wzywam mojego skryptu (nie całkiem NET < 3 powershell drogę :)

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; 
} 

Tajemnica pogłębia, dodaje tej linii do moich zadań gwintowanych

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

Po uruchomieniu skryptu z IIS otrzymuję wiadomość z każdej maszyny. Tak jak pokazuje moje użycie pamięci RAM, wszystkie zadania są uruchamiane, ale dane wyjściowe nie są zwracane poprawnie, a wątek hosta po prostu tam jest ... czekaj ...

Odpowiedz

3

Znalazłem rozwiązanie. To jest zakleszczenie spowodowane wywołaniem

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

Zaraz po sobie. Zamiast tego następuje http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandarderror.aspx#Y95 i zrobił to w zamian:

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; 
} 

Nie więcej wiszące :)

0

możesz użyć czegoś takiego, aby zobaczyć polecenia i wyjście ...

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

Jestem zainteresowany, aby wiedzieć, jak jesteś nazywając go z ASP.NET, jak również?

+0

Dzięki, postaram rzecz rejestrowania – Daniel

+0

@Daniel, cool - daj mi znać jak poszło – Matt

+0

Niezbyt dobrze: P Loguje całą rzecz, gdy uruchomię go z konsoli, ale wykonanie go z IIS i daje mnie to: – Daniel

7

Na marginesie, masz jakiś niepotrzebnych rzeczy dzieje.

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 już tworzy listę zadań; nie trzeba tego robić w zmiennej $ jobs i nie trzeba ich wyliczać, aby czekać.

Oczywiście, możesz użyć $ jobs dla czegoś innego w swoim kodzie - ale chciałeś tylko, aby inni ludzie widzieli tę alternatywę.

Powiązane problemy