我正在尝试用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个结果,然后主机线程只是坐在那里。(直到我用fire杀死它,我的输出返回到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使用情况所示,所有作业都运行了,但是输出没有正确返回,并且我的主机线程只是坐在那里…等待…
需要注意的是,这里有一些不必要的东西。
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用于代码中的其他内容—但只是想确保其他人看到这个替代。
我找到了解决方案。调用
会导致死锁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;
}
不再挂起
您可以使用这样的代码来查看命令和输出…
$logfile = "C:Documents and SettingsusernameMy DocumentsWindowsPowerShelllogs$(Get-Date -uformat "%Y%m%d - %H%M%S").log"
Start-Transcript -Path $logfile
我很想知道你是如何从ASP调用它的。还有网络?