public void IsRunningTest() { ExitStatus running = ExitStatus.Executing; ExitStatus completed = ExitStatus.Completed; Assert.IsTrue(running.IsRunning()); Assert.IsFalse(completed.IsRunning()); }
/// <summary> /// Wraps command execution into system process call. /// </summary> /// <returns></returns> /// <exception cref="Exception"></exception> public RepeatStatus Execute(StepContribution contribution, ChunkContext chunkContext) { if (Logger.IsTraceEnabled) { Logger.Trace("*** Executing PowerShell Script File: {0}", ScriptResource.GetFullPath()); } //=> PowerShell will throw an error if we do not Suppress ambient transaction... // see https://msdn.microsoft.com/en-us/library/system.transactions.transaction.current(v=vs.110).aspx#NotExistJustToMakeTheAElementVisible using (var transactionScope = new TransactionScope(TransactionScopeOption.Suppress)) { //=> Runspace configuration information includes the assemblies, commands, format and type files, // providers, and scripts that are available within the runspace. RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create(); //Creates a single runspace that uses the default host and runspace configuration using (Runspace runSpace = RunspaceFactory.CreateRunspace(runspaceConfiguration)) { //=> When this runspace is opened, the default host and runspace configuration // that are defined by Windows PowerShell will be used. runSpace.Open(); //=> Set Variables so they are available to user script... if (Variables != null && Variables.Any()) { foreach (KeyValuePair<string, object> variable in Variables) { runSpace.SessionStateProxy.SetVariable(variable.Key, variable.Value); } } //=> this is exit status variables to be tested on exit from power shell script... // it is defined in PwerShell global scope...and must be set by scipt writer on exit... runSpace.SessionStateProxy.SetVariable("ScriptExitStatus", _scriptExitStatus); //=> Allows the execution of commands from a CLR //RunspaceInvoke scriptInvoker = new RunspaceInvoke(runSpace); //scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted"); using (PowerShell psInstance = PowerShell.Create()) { try { // prepare a new collection to store output stream objects PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>(); outputCollection.DataAdded += AllStreams_DataAdded; psInstance.Streams.Error.DataAdded += AllStreams_DataAdded; psInstance.Streams.Verbose.DataAdded += AllStreams_DataAdded; psInstance.Streams.Warning.DataAdded += AllStreams_DataAdded; psInstance.Streams.Debug.DataAdded += AllStreams_DataAdded; psInstance.Runspace = runSpace; //=> This tasklet should be in the same dll as ExitStatus, i.e. Summer.Batch.Core.dll // we need to get the path to loaded Summer.Batch.Core.dll so we can load it in PowerShell var assemblyLocation = System.Reflection.Assembly.GetExecutingAssembly().Location; //=> need to load Summer.Batch.Core into runspace so we can reference ExitStatus psInstance.AddScript("[System.Reflection.Assembly]::LoadFrom(\""+assemblyLocation+"\")").AddStatement(); //=> add user command and its parameters... psInstance.AddCommand(ScriptResource.GetFullPath()); if (Parameters != null && Parameters.Any()) { foreach (KeyValuePair<string, object> variable in Parameters) { psInstance.AddParameter(variable.Key, variable.Value); } } //=> Invoke Asynchronously... IAsyncResult asyncResult = psInstance.BeginInvoke<PSObject, PSObject>(null, outputCollection); // do something else until execution has completed. long t0 = DateTime.Now.Ticks; while (!asyncResult.IsCompleted) { //=> take a nap and let script do its job... Thread.Sleep(new TimeSpan(_checkInterval)); //=> to check if job was told to stop... CheckStoppingState(chunkContext); //=> lets make sure we did not exceed alloted time... long timeFromT0 = (long)(new TimeSpan(DateTime.Now.Ticks - t0)).TotalMilliseconds; if (timeFromT0 > _timeout) { //=> Stop PowerShell... psInstance.Stop(); //=> behave based on TimeoutBehaviorOption if (_timeoutBehavior.Equals(TimeoutBehaviorOption.SetExitStatusToFailed)) { contribution.ExitStatus = ExitStatus.Failed; break; } else if (_timeoutBehavior.Equals(TimeoutBehaviorOption.ThrowException)) { //=> lets dump what we got before throwing an error... LogStreams(); throw new FatalStepExecutionException("Execution of PowerShell script exceeded allotted time.", null); } } else if (_execution.TerminateOnly) { //=> Stop PowerShell... psInstance.Stop(); //=> lets dump what we got before throwing an error... LogStreams(); throw new JobInterruptedException( string.Format("Job interrupted while executing PowerShell script '{0}'", ScriptResource.GetFilename())); } else if (_stopped) { psInstance.Stop(); contribution.ExitStatus = ExitStatus.Stopped; break; } } // end while scope //=> Wait to the end of execution... //psInstance.EndInvoke(_asyncResult); //NOTE: asyncResult.IsCompleted will be set to true if PowerShell.Stop was called or // PowerShell completed its work //=> if status not yet set (script completed)...handle completion... if (contribution.ExitStatus.IsRunning()) { //=> script needs to set exit code...if exit code not set we assume 0 var lastExitCode = (int)runSpace.SessionStateProxy.PSVariable.GetValue("LastExitCode", 0); _scriptExitStatus = runSpace.SessionStateProxy.GetVariable("ScriptExitStatus") as ExitStatus; //=> set exit status... if (_scriptExitStatus != null && !_scriptExitStatus.IsRunning()) { if (Logger.IsTraceEnabled) { Logger.Trace("***> ScriptExitStatus returned by script => {0}", _scriptExitStatus); } contribution.ExitStatus = _scriptExitStatus; } else //=> let user decide on ExitStatus { if (Logger.IsTraceEnabled) { if (_scriptExitStatus == null) { Logger.Trace("***> ScriptExitStatus is null. Using PowerShellExitCodeMapper to determine ExitStatus."); } else if (_scriptExitStatus.IsRunning()) { Logger.Trace("***> ScriptExitStatus is EXECUTING or UNKNOWN. Using PowerShellExitCodeMapper to determine ExitStatus."); } } if (PowerShellExitCodeMapper != null) { //=> determine exit status using User Provided PowerShellExitCodeMapper contribution.ExitStatus = PowerShellExitCodeMapper.GetExitStatus(lastExitCode); } else //at this point we are not able to determine exit status, user needs to fix this... { //=> lets dump what we got before throwing an error... LogStreams(); throw new FatalStepExecutionException( "PowerShellTasklet is not able to determine ExitStatus. ScriptExitStatus is null or (is EXECUTING or UNKNOWN) and "+ "PowerShellExitCodeMapper is NOT defined. Please set $global:ScriptExitStatus or define PowerShellExitCodeMapper.", null); } } } if (Logger.IsInfoEnabled) { Logger.Info("PowerShell execution exit status [{0}]", contribution.ExitStatus); } //=> output captured stream data to Log... LogStreams(); } catch (RuntimeException ex) { Logger.Error(ex.Message); throw; } } // end PowerShell Scope //=> close Runspace... runSpace.Close(); //=> we are done... return RepeatStatus.Finished; } // end of Runspace Scope }// end of TransactionScope }
/// <summary> /// Wraps command execution into system process call. /// </summary> /// <returns></returns> /// <exception cref="Exception"></exception> public RepeatStatus Execute(StepContribution contribution, ChunkContext chunkContext) { if (Logger.IsTraceEnabled) { Logger.Trace("*** Executing PowerShell Script File: {0}", ScriptResource.GetFullPath()); } //=> PowerShell will throw an error if we do not Suppress ambient transaction... // see https://msdn.microsoft.com/en-us/library/system.transactions.transaction.current(v=vs.110).aspx#NotExistJustToMakeTheAElementVisible using (var transactionScope = new TransactionScope(TransactionScopeOption.Suppress)) { //=> Runspace configuration information includes the assemblies, commands, format and type files, // providers, and scripts that are available within the runspace. RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create(); //Creates a single runspace that uses the default host and runspace configuration using (Runspace runSpace = RunspaceFactory.CreateRunspace(runspaceConfiguration)) { //=> When this runspace is opened, the default host and runspace configuration // that are defined by Windows PowerShell will be used. runSpace.Open(); //=> Set Variables so they are available to user script... if (Variables != null && Variables.Any()) { foreach (KeyValuePair <string, object> variable in Variables) { runSpace.SessionStateProxy.SetVariable(variable.Key, variable.Value); } } //=> this is exit status variables to be tested on exit from power shell script... // it is defined in PwerShell global scope...and must be set by scipt writer on exit... runSpace.SessionStateProxy.SetVariable("ScriptExitStatus", _scriptExitStatus); //=> Allows the execution of commands from a CLR //RunspaceInvoke scriptInvoker = new RunspaceInvoke(runSpace); //scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted"); using (PowerShell psInstance = PowerShell.Create()) { try { // prepare a new collection to store output stream objects PSDataCollection <PSObject> outputCollection = new PSDataCollection <PSObject>(); outputCollection.DataAdded += AllStreams_DataAdded; psInstance.Streams.Error.DataAdded += AllStreams_DataAdded; psInstance.Streams.Verbose.DataAdded += AllStreams_DataAdded; psInstance.Streams.Warning.DataAdded += AllStreams_DataAdded; psInstance.Streams.Debug.DataAdded += AllStreams_DataAdded; psInstance.Runspace = runSpace; //=> This tasklet should be in the same dll as ExitStatus, i.e. Summer.Batch.Core.dll // we need to get the path to loaded Summer.Batch.Core.dll so we can load it in PowerShell var assemblyLocation = System.Reflection.Assembly.GetExecutingAssembly().Location; //=> need to load Summer.Batch.Core into runspace so we can reference ExitStatus psInstance.AddScript("[System.Reflection.Assembly]::LoadFrom(\"" + assemblyLocation + "\")").AddStatement(); //=> add user command and its parameters... psInstance.AddCommand(ScriptResource.GetFullPath()); if (Parameters != null && Parameters.Any()) { foreach (KeyValuePair <string, object> variable in Parameters) { psInstance.AddParameter(variable.Key, variable.Value); } } //=> Invoke Asynchronously... IAsyncResult asyncResult = psInstance.BeginInvoke <PSObject, PSObject>(null, outputCollection); // do something else until execution has completed. long t0 = DateTime.Now.Ticks; while (!asyncResult.IsCompleted) { //=> take a nap and let script do its job... Thread.Sleep(new TimeSpan(_checkInterval)); //=> to check if job was told to stop... CheckStoppingState(chunkContext); //=> lets make sure we did not exceed alloted time... long timeFromT0 = (long)(new TimeSpan(DateTime.Now.Ticks - t0)).TotalMilliseconds; if (timeFromT0 > _timeout) { //=> Stop PowerShell... psInstance.Stop(); //=> behave based on TimeoutBehaviorOption if (_timeoutBehavior.Equals(TimeoutBehaviorOption.SetExitStatusToFailed)) { contribution.ExitStatus = ExitStatus.Failed; break; } else if (_timeoutBehavior.Equals(TimeoutBehaviorOption.ThrowException)) { //=> lets dump what we got before throwing an error... LogStreams(); throw new FatalStepExecutionException("Execution of PowerShell script exceeded allotted time.", null); } } else if (_execution.TerminateOnly) { //=> Stop PowerShell... psInstance.Stop(); //=> lets dump what we got before throwing an error... LogStreams(); throw new JobInterruptedException( string.Format("Job interrupted while executing PowerShell script '{0}'", ScriptResource.GetFilename())); } else if (_stopped) { psInstance.Stop(); contribution.ExitStatus = ExitStatus.Stopped; break; } } // end while scope //=> Wait to the end of execution... //psInstance.EndInvoke(_asyncResult); //NOTE: asyncResult.IsCompleted will be set to true if PowerShell.Stop was called or // PowerShell completed its work //=> if status not yet set (script completed)...handle completion... if (contribution.ExitStatus.IsRunning()) { //=> script needs to set exit code...if exit code not set we assume 0 var lastExitCode = (int)runSpace.SessionStateProxy.PSVariable.GetValue("LastExitCode", 0); _scriptExitStatus = runSpace.SessionStateProxy.GetVariable("ScriptExitStatus") as ExitStatus; //=> set exit status... if (_scriptExitStatus != null && !_scriptExitStatus.IsRunning()) { if (Logger.IsTraceEnabled) { Logger.Trace("***> ScriptExitStatus returned by script => {0}", _scriptExitStatus); } contribution.ExitStatus = _scriptExitStatus; } else //=> let user decide on ExitStatus { if (Logger.IsTraceEnabled) { if (_scriptExitStatus == null) { Logger.Trace("***> ScriptExitStatus is null. Using PowerShellExitCodeMapper to determine ExitStatus."); } else if (_scriptExitStatus.IsRunning()) { Logger.Trace("***> ScriptExitStatus is EXECUTING or UNKNOWN. Using PowerShellExitCodeMapper to determine ExitStatus."); } } if (PowerShellExitCodeMapper != null) { //=> determine exit status using User Provided PowerShellExitCodeMapper contribution.ExitStatus = PowerShellExitCodeMapper.GetExitStatus(lastExitCode); } else //at this point we are not able to determine exit status, user needs to fix this... { //=> lets dump what we got before throwing an error... LogStreams(); throw new FatalStepExecutionException( "PowerShellTasklet is not able to determine ExitStatus. ScriptExitStatus is null or (is EXECUTING or UNKNOWN) and " + "PowerShellExitCodeMapper is NOT defined. Please set $global:ScriptExitStatus or define PowerShellExitCodeMapper.", null); } } } if (Logger.IsInfoEnabled) { Logger.Info("PowerShell execution exit status [{0}]", contribution.ExitStatus); } //=> output captured stream data to Log... LogStreams(); } catch (RuntimeException ex) { Logger.Error(ex.Message); throw; } } // end PowerShell Scope //=> close Runspace... runSpace.Close(); //=> we are done... return(RepeatStatus.Finished); } // end of Runspace Scope } // end of TransactionScope }