/// <summary> /// In a script block, we only provide the pipeline as the automatic $input variable, but call it only once /// </summary> public override void ProcessRecords() { // TODO: provide the automatic $input variable // TODO: currently we don't support "cmdlet scripts", i.e. functions that behave like cmdlets. // TODO: Investigate the usage of different function blocks properly before implementing them //set the execution context of the runspace to the new context for execution in it SwitchToOwnScope(); try { _scriptBlockInfo.ScriptBlock.Ast.Visit(new ExecutionVisitor(ExecutionContext, CommandRuntime, false)); } catch (ExitException e) { if (_fromFile) { _exitCode = e.ExitCode; ExecutionContext.SetVariable("global:LASTEXITCODE", e.ExitCode); } else { throw; } } finally //make sure we switch back to the original execution context, no matter what happened { RestoreOriginalScope(); } }
private void ProcessExited(object sender, System.EventArgs e) { ExecutionContext.SetVariable("global:LASTEXITCODE", _process.ExitCode); ExecutionContext.SetVariable("global:?", _process.ExitCode == 0); // PS also just compares against null _process.Dispose(); _process = null; }
public void SetVariable(string name, object value) { if (string.IsNullOrEmpty(name)) { throw new NullReferenceException("Variable name can't be empty."); } ExecutionContext.SetVariable(name, value); }
private void SetArgsVariableFromUnboundArgs(List <CommandParameter> unboundArguments) { var otherArgs = new List <object>(); foreach (var unboundArg in unboundArguments) { var nameSet = false; if (!String.IsNullOrEmpty(unboundArg.Name)) { otherArgs.Add(unboundArg.GetDecoratedName()); nameSet = true; } if (unboundArg.Value != null || !nameSet || unboundArg.HasExplicitArgument) { otherArgs.Add(unboundArg.Value); } } _executionContext.SetVariable("Args", otherArgs.ToArray()); unboundArguments.Clear(); }
private void BindArguments() { ReadOnlyCollection <ParameterAst> scriptParameters = _scriptBlockInfo.GetParameters(); for (int i = 0; i < scriptParameters.Count; ++i) { ParameterAst scriptParameter = scriptParameters[i]; CommandParameter parameter = GetParameterByPosition(i); object parameterValue = GetParameterValue(scriptParameter, parameter); ExecutionContext.SetVariable(scriptParameter.Name.VariablePath.UserPath, parameterValue); } }
public override Collection <PSObject> Invoke(IEnumerable input) { // TODO: run the pipeline on another thread and wait for the completion // TODO: nested pipelines: make sure we are running in the same thread as another pipeline, because // nested pipelines aren't allowed to run in their own thread. This ensures that there is a "parent" pipeline Input.Write(input, true); // in a pipeline, the first command enters *always* the ProcessRecord phase, the following commands only // if the previous command generated output. To make sure the first command enters that phase, add null // if nothing else is in the input stream if (_inputStream.Count == 0) { Input.Write(null); } string errorId = "BuildingPipelineProcessorFailed"; ExecutionContext context = _runspace.ExecutionContext.Clone(); RerouteExecutionContext(context); try { if (!_pipelineStateInfo.State.Equals(PipelineState.NotStarted)) { throw new InvalidPipelineStateException("Pipeline cannot be started", _pipelineStateInfo.State, PipelineState.NotStarted); } var pipelineProcessor = BuildPipelineProcessor(context); _runspace.AddRunningPipeline(this); SetPipelineState(PipelineState.Running); errorId = "TerminatingError"; pipelineProcessor.Execute(context); SetPipelineState(PipelineState.Completed); } catch (ExitException ex) { // Toplevel pipeline if (!IsNested) { _runspace.PSHost.SetShouldExit(ex.ExitCode); } else { // nested pipelines propagate the exit command throw; } } catch (Exception ex) { // in case of throw statement, parse error, or "ThrowTerminatingError" // just add to error variable and rethrow that thing var errorRecord = (ex is IContainsErrorRecord) ? ((IContainsErrorRecord)ex).ErrorRecord : new ErrorRecord(ex, errorId, ErrorCategory.InvalidOperation, null); context.AddToErrorVariable(errorRecord); context.SetVariable("global:?", false); // last command was definitely not successfull throw; } _runspace.RemoveRunningPipeline(this); return(Output.NonBlockingRead()); }
private static PSPropertyInfo EvaluateProperty(object property, PSObject psobj, ExecutionContext executionContext) { property = PSObject.Unwrap(property); var propName = property as string; if (propName != null) { var prop = psobj.Properties[propName]; return prop ?? new PSNoteProperty(propName, ""); } // check if it's a Hashtable. We can then have expression=<ScriptBlock> and label=<string> or name=<string> var hashtable = property as Hashtable; if (hashtable != null) { // we have a strange logice here, but we'll just do it as Powershell // if label and name is contained in the hashset, "name" member will be set (and throw, if already existing) if (hashtable.ContainsKey("label")) { hashtable["name"] = hashtable["label"]; hashtable.Remove("label"); } // also, we really care that we only have "name" and "expression" keys, otherwise we throw an error... foreach (var key in hashtable.Keys) { var keyStr = key.ToString(); if (keyStr.Equals("name", StringComparison.InvariantCultureIgnoreCase)) { propName = hashtable[key].ToString(); } else if (keyStr.Equals("expression", StringComparison.InvariantCultureIgnoreCase)) { // should be a script block, we will check this later property = PSObject.Unwrap(hashtable[key]); } else { throw new NotSupportedException(String.Format("Invalid key '{0}'", keyStr)); } } } // now it must be a scriptblock that can be evaluated (either from the hastable or the property itself) var scriptBlock = property as ScriptBlock; if (scriptBlock == null) { var msg = String.Format("The property '{0}' couldn't be converted to a string, Hashtable, or a ScriptBlock", property.GetType().Name); throw new PSInvalidOperationException(msg); } if (propName == null) { propName = scriptBlock.ToString(); } var pipeline = executionContext.CurrentRunspace.CreateNestedPipeline(); pipeline.Commands.Add(new Command(scriptBlock.Ast as ScriptBlockAst, true)); // TODO: hack? we need to set the $_ variable var oldVar = executionContext.GetVariable("_"); executionContext.SetVariable("_", psobj); Collection<PSObject> results = null; try { results = pipeline.Invoke(); } finally { if (oldVar != null) { executionContext.SessionState.PSVariable.Set(oldVar); } else { executionContext.SessionState.PSVariable.Set("_", null); } } PSObject value; if (results.Count == 0) { value = PSObject.AsPSObject(null); } else if (results.Count == 1) { value = results[0]; } else { value = PSObject.AsPSObject(new List<PSObject>(results).ToArray()); } return new PSNoteProperty(propName, value); }
public override void EndProcessing() { // TODO: process end clause. remember to switch scope ExecutionContext.SetVariable("global:?", _exitCode == null || _exitCode == 0); }