2011-07-07 61 views
5

我目前正在嘗試使用從IIS啓動的PowerShell創建線程清理腳本。 我使用powershell remoting進行線程化「由擁有者殺死進程」,從與我的清理腳本相同的服務器列表運行,並且沒有任何問題。當從ASP.NET運行時,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應用程序運行它時,我爲我的28個服務器中的每一個都獲得「」開始作業:$ comp「」,但只有第14個結果,然後主機線程就在那裏。 (直到我用火殺死它,並且我的輸出返回到asp.net網頁)

我無法看到當我從asp.net頁面運行腳本時會發生什麼情況。我可以看到是cpu/ram的使用下降到相同的水平,當我從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運行我的腳本時,我收到來自每臺機器的消息。 正如我的RAM使用顯示,所有的工作都運行,但輸出沒有正確返回,並且我的主機線程剛好在那裏...等待...

回答

3

我找到了解決方案。這是致命的死鎖

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

你可以使用類似這樣的東西來查看命令和輸出...

$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調用它嗎?

+0

謝謝,我會嘗試伐木的事情 – Daniel

+0

@Daniel,酷 - 讓我知道它是怎麼回事 – Matt

+0

不好:P 它記錄整個事情,當我從控制檯運行它,但執行它從IIS,它給我: – Daniel

7

作爲一個說明,你有一些不必要的東西怎麼回事。

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已經構建了一個工作列表;在$ job變量中不需要這樣做,也不需要枚舉它們來等待。

當然,您可以使用$作爲代碼中的其他東西 - 但只是想確保其他人看到這個選擇。