我目前正在尝试使用从IIS启动的PowerShell构建线程清理脚本。 我使用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用法显示的那样,所有作业都在运行,但输出没有正确返回,我的主机线程就在那里......等待...
答案 0 :(得分: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已经构建了一份工作清单;在$ jobs变量中没有必要这样做,也不需要枚举它们来进行等待。
当然,你可以在你的代码中使用$ jobs来做其他事情 - 但只是想确保其他人看到这个替代方案。
答案 1 :(得分: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;
}
不再挂:)
答案 2 :(得分: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中调用它的?