Question:
I am working on an asp.net mvc web application, and i have the following code which define a loop over a list of servers and execute PowerCli commands inside my asp.net mvc for each server:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//Start Loop var shell = PowerShell.Create(); var shell2 = PowerShell.Create(); var shell3 = PowerShell.Create(); string PsCmd = "add-pssnapin VMware.VimAutomation.Core; $vCenterServer = '" + vCenterName + "';$vCenterAdmin = '" + vCenterUsername + "' ;$vCenterPassword = '" + vCenterPassword + "';" + System.Environment.NewLine; PsCmd = PsCmd + "$VIServer = Connect-VIServer -Server $vCenterServer -User $vCenterAdmin -Password $vCenterPassword;" + System.Environment.NewLine; PsCmd = PsCmd + "Get-VMHost " + System.Environment.NewLine; string PsCmd2 = "add-pssnapin VMware.VimAutomation.Core; $vCenterServer = '" + vCenterName + "';$vCenterAdmin = '" + vCenterUsername + "' ;$vCenterPassword = '" + vCenterPassword + "';" + System.Environment.NewLine; PsCmd2 = PsCmd2 + "$VIServer = Connect-VIServer -Server $vCenterServer -User $vCenterAdmin -Password $vCenterPassword;" + System.Environment.NewLine; PsCmd2 = PsCmd2 + " Get-VMHost " + vCenterName + "| Get-VMHostNetworkAdapter -VMKernel" + System.Environment.NewLine; shell.Commands.AddScript(PsCmd); shell2.Commands.AddScript(PsCmd2); dynamic results = shell.Invoke(); dynamic results2 = shell2.Invoke(); // end of loop |
but i have noted that sometimes the shell commands will hang and the execution never ends,, so can i define a timeout behavior ,, so that after 5 minutes to skip the commands if no results were returned …
Answer:
You will have to roll your own timeout command. Below is code I wrote based on a MSDN Blog entry by Keith Babinec – Executing PowerShell scripts from C#. I wrote the sample in Console Application for demonstration purposes only. I find it easier to see what is happen. You can convert it to Asp.Net application by removing the Console Output and other adjustments.
Here is Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
using System; using System.Management.Automation; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string script = "Write-Host \"Testing lopping...\"" + Environment.NewLine + "for ($i=1; $i -le 5; $i++)" + Environment.NewLine + "{" + Environment.NewLine + "Write-Output $i" + Environment.NewLine + "Start-Sleep -s 3" + Environment.NewLine + "}" + Environment.NewLine + "Write-Host \"Done!\"" + Environment.NewLine; PowerShell shell = PowerShell.Create(); shell.AddScript(script); PowerShellHelper helper = new PowerShellHelper(shell); try { // the script above should take 15 seconds to execute // do timeout of 10 minutes helper.ExecuteAsynchronously(new TimeSpan(0, 10, 0)); // do a really short timeout - 2 seconds helper.ExecuteAsynchronously(new TimeSpan(0, 0, 2)); } catch(TimeoutException te) { Console.WriteLine("\n\nScript took long!"); } Console.WriteLine("Demo Finish"); Console.ReadLine(); } } } |
And here is PowerShellHelper.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
using System; using System.Management.Automation; using System.Threading; // This code was build from MSDN Blogs entry by Keith Babinec // http://blogs.msdn.com/b/kebab/archive/2014/04/28/executing-powershell-scripts-from-c.aspx namespace ConsoleApplication1 { class PowerShellHelper { private PowerShell shell_; public PowerShellHelper(PowerShell shell) { shell_ = shell; } public void ExecuteAsynchronously(TimeSpan timeout) { // prepare a new collection to store output stream objects PSDataCollection outputCollection.DataAdded += outputCollection_DataAdded; // begin invoke execution on the pipeline // use this overload to specify an output stream buffer IAsyncResult result = shell_.BeginInvoke // start the timer DateTime startTime = DateTime.Now; // do something else until execution has completed. // this could be sleep/wait, or perhaps some other work while (result.IsCompleted == false) { Console.WriteLine("Waiting for pipeline to finish..."); Thread.Sleep(100); // we check on our timeout here TimeSpan elasped = DateTime.Now.Subtract(startTime); if (elasped > timeout) { // we can do a few things here, I like to throw exception throw new TimeoutException("Powershell script taking too long"); } } Console.WriteLine("Execution has stopped. The pipeline state: " + shell_.InvocationStateInfo.State); foreach (PSObject outputItem in outputCollection) { //TODO: handle/process the output items if required if (outputItem != null) { Console.WriteLine(outputItem.BaseObject.ToString()); } } } /// /// Event handler for when data is added to the output stream. /// /// Contains the complete PSDataCollection of all output items. /// Contains the index ID of the added collection item and the ID of the PowerShell instance this event belongs to. private void outputCollection_DataAdded(object sender, DataAddedEventArgs e) { // do something when an object is written to the output stream Console.WriteLine("Object added to output."); } } } |