2011-07-07 16 views
5

Actualmente estoy tratando de crear una secuencia de comandos de limpieza con threaded con powershell, iniciada desde un IIS. He realizado un "Proceso de eliminación por parte del propietario" mediante PowerShell remoting, que se ejecuta desde la misma lista de servidores que mi script de limpieza, y eso no representa ningún problema.Powershell start-job, wait-job, host thread nunca sale cuando se ejecuta desde 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 

cuando corro mi script desde la consola de PowerShell, todo funciona perfectamente, hilo principal comienza 28 nuevos procesos, que comienzan una conexión de comunicación remota a cada servidor, y espera a que todos los puestos de trabajo para terminar. Cuando terminan, obtengo mi salida y el hilo de host existe. Todo funcionando según lo planeado.

No es así cuando lo ejecuto desde mi aplicación asp.net, obtengo "" Trabajo iniciado en: $ comp "" para cada uno de mis 28 servidores, pero solo un resultado de los primeros 14, y luego el hilo de host solo se sienta allí. (hasta que lo mato con fuego, y mi salida se devuelve a la página web asp.net)

No tengo manera de ver qué sucede en el script cuando lo ejecuto desde la página asp.net. Todo lo que puedo ver El uso de cpu/ram cae a los mismos niveles que cuando lo ejecuto desde PSconsole, pero mi hilo principal nunca se cierra. Así que creo que el script funciona como se supone, pero mi página web se cuelga hasta que se cierra el hilo principal (lo que nunca ocurre, como se dijo).


Ésta es la forma en que llamo mi guión (no el bonito .net < manera PowerShell 3 :)

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

El misterio va aumentando, añade esta línea a mis trabajos roscados

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

Y cuando ejecuto mi script desde el IIS, recibo un mensaje de cada máquina. Así como se muestra el uso de RAM, todos los trabajos se ejecutan, pero la salida no se devuelve correctamente, y mi hilo de host simplemente se sienta allí ... esperando ...

Respuesta

3

Encontré la solución. Es un punto muerto causado por la llamada

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

Justo después de la otra. En lugar de eso siguieron http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandarderror.aspx#Y95 e hizo esto en su lugar:

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

No más colgando :)

0

podría usar algo como esto para ver los comandos y la salida ...

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

¿Me interesa saber cómo lo está llamando desde ASP.Net también?

+0

Gracias, voy a tratar el asunto de registro – Daniel

+0

@ Daniel, fresco - que me haga saber cómo va – Matt

+0

No es así: P Se registra toda la cosa cuando lo ejecuto desde la consola, pero ejecutarlo desde el IIS y Da mí esto: – Daniel

7

Como nota, tienes algunas cosas innecesarias pasando.

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 ya crea una lista de trabajos; no es necesario hacerlo en una variable $ jobs, y no es necesario enumerarlos para hacer la espera.

Por supuesto, puede usar $ jobs para otra cosa en su código, pero solo quería asegurarse de que otras personas vean esta alternativa.

Cuestiones relacionadas