internal void InvokeWithPipeImpl(ScriptBlockClauseToInvoke clauseToInvoke, bool createLocalScope, Dictionary<string, ScriptBlock> functionsToDefine, List<PSVariable> variablesToDefine, ErrorHandlingBehavior errorHandlingBehavior, object dollarUnder, object input, object scriptThis, Pipe outputPipe, InvocationInfo invocationInfo, params object[] args) { if (clauseToInvoke == ScriptBlockClauseToInvoke.Begin && !HasBeginBlock) { return; } else if (clauseToInvoke == ScriptBlockClauseToInvoke.Process && !HasProcessBlock) { return; } else if (clauseToInvoke == ScriptBlockClauseToInvoke.End && !HasEndBlock) { return; } ExecutionContext context = GetContextFromTLS(); Diagnostics.Assert(SessionStateInternal == null || SessionStateInternal.ExecutionContext == context, "The scriptblock is being invoked in a runspace different than the one where it was created"); if (context.CurrentPipelineStopping) { throw new PipelineStoppedException(); } // Validate at the arguments are consistent. The only public API that gets you here never sets createLocalScope to false... Diagnostics.Assert(createLocalScope == true || functionsToDefine == null, "When calling ScriptBlock.InvokeWithContext(), if 'functionsToDefine' != null then 'createLocalScope' must be true"); Diagnostics.Assert(createLocalScope == true || variablesToDefine == null, "When calling ScriptBlock.InvokeWithContext(), if 'variablesToDefine' != null then 'createLocalScope' must be true"); if (args == null) { args = Utils.EmptyArray<object>(); } bool runOptimized = context._debuggingMode > 0 ? false : createLocalScope; var codeToInvoke = GetCodeToInvoke(ref runOptimized, clauseToInvoke); if (codeToInvoke == null) return; if (outputPipe == null) { // If we don't have a pipe to write to, we need to discard all results. outputPipe = new Pipe { NullPipe = true }; } var locals = MakeLocalsTuple(runOptimized); if (dollarUnder != AutomationNull.Value) { locals.SetAutomaticVariable(AutomaticVariable.Underbar, dollarUnder, context); } if (input != AutomationNull.Value) { locals.SetAutomaticVariable(AutomaticVariable.Input, input, context); } if (scriptThis != AutomationNull.Value) { locals.SetAutomaticVariable(AutomaticVariable.This, scriptThis, context); } SetPSScriptRootAndPSCommandPath(locals, context); var oldShellFunctionErrorOutputPipe = context.ShellFunctionErrorOutputPipe; var oldExternalErrorOutput = context.ExternalErrorOutput; var oldScopeOrigin = context.EngineSessionState.CurrentScope.ScopeOrigin; var oldSessionState = context.EngineSessionState; // If the script block has a different language mode than the current, // change the language mode. PSLanguageMode? oldLanguageMode = null; PSLanguageMode? newLanguageMode = null; if ((this.LanguageMode.HasValue) && (this.LanguageMode != context.LanguageMode)) { oldLanguageMode = context.LanguageMode; newLanguageMode = this.LanguageMode; } Dictionary<string, PSVariable> backupWhenDotting = null; try { var myInvocationInfo = invocationInfo; if (myInvocationInfo == null) { var callerFrame = context.Debugger.GetCallStack().LastOrDefault(); var extent = (callerFrame != null) ? callerFrame.FunctionContext.CurrentPosition : Ast.Extent; myInvocationInfo = new InvocationInfo(null, extent, context); } locals.SetAutomaticVariable(AutomaticVariable.MyInvocation, myInvocationInfo, context); if (SessionStateInternal != null) context.EngineSessionState = SessionStateInternal; // If we don't want errors written, hide the error pipe. switch (errorHandlingBehavior) { case ErrorHandlingBehavior.WriteToCurrentErrorPipe: // no need to do anything break; case ErrorHandlingBehavior.WriteToExternalErrorPipe: context.ShellFunctionErrorOutputPipe = null; break; case ErrorHandlingBehavior.SwallowErrors: context.ShellFunctionErrorOutputPipe = null; context.ExternalErrorOutput = new DiscardingPipelineWriter(); break; } if (createLocalScope) { var newScope = context.EngineSessionState.NewScope(false); context.EngineSessionState.CurrentScope = newScope; newScope.LocalsTuple = locals; // Inject passed in functions into the scope if (functionsToDefine != null) { foreach (var def in functionsToDefine) { if (string.IsNullOrWhiteSpace(def.Key)) { PSInvalidOperationException e = PSTraceSource.NewInvalidOperationException( ParserStrings.EmptyFunctionNameInFunctionDefinitionDictionary); e.SetErrorId("EmptyFunctionNameInFunctionDefinitionDictionary"); throw e; } if (def.Value == null) { PSInvalidOperationException e = PSTraceSource.NewInvalidOperationException( ParserStrings.NullFunctionBodyInFunctionDefinitionDictionary, def.Key); e.SetErrorId("NullFunctionBodyInFunctionDefinitionDictionary"); throw e; } newScope.FunctionTable.Add(def.Key, new FunctionInfo(def.Key, def.Value, context)); } } // Inject passed in variables into the scope if (variablesToDefine != null) { int index = 0; foreach (var psvar in variablesToDefine) { // Check for null entries. if (psvar == null) { PSInvalidOperationException e = PSTraceSource.NewInvalidOperationException( ParserStrings.NullEntryInVariablesDefinitionList, index); e.SetErrorId("NullEntryInVariablesDefinitionList"); throw e; } string name = psvar.Name; Diagnostics.Assert(!(string.Equals(name, "this") || string.Equals(name, "_") || string.Equals(name, "input")), "The list of variables to set in the scriptblock's scope cannot contain 'this', '_' or 'input'. These variables should be removed before passing the collection to this routine."); index++; newScope.Variables.Add(name, psvar); } } } else { if (context.EngineSessionState.CurrentScope.LocalsTuple == null) { // If the locals tuple is, that means either: // * we're invoking a script block for a module // * something unexpected context.EngineSessionState.CurrentScope.LocalsTuple = locals; } else { context.EngineSessionState.CurrentScope.DottedScopes.Push(locals); backupWhenDotting = new Dictionary<string, PSVariable>(); } } // Set the language mode if (newLanguageMode.HasValue) { context.LanguageMode = newLanguageMode.Value; } args = BindArgumentsForScriptblockInvoke( (RuntimeDefinedParameter[])RuntimeDefinedParameters.Data, args, context, !createLocalScope, backupWhenDotting, locals); locals.SetAutomaticVariable(AutomaticVariable.Args, args, context); context.EngineSessionState.CurrentScope.ScopeOrigin = CommandOrigin.Internal; var functionContext = new FunctionContext { _executionContext = context, _outputPipe = outputPipe, _localsTuple = locals, _scriptBlock = this, _file = this.File, _debuggerHidden = this.DebuggerHidden, _debuggerStepThrough = this.DebuggerStepThrough, _sequencePoints = SequencePoints, }; ScriptBlock.LogScriptBlockStart(this, context.CurrentRunspace.InstanceId); try { codeToInvoke(functionContext); } finally { ScriptBlock.LogScriptBlockEnd(this, context.CurrentRunspace.InstanceId); } } catch (TargetInvocationException tie) { // DynamicInvoke always wraps, so unwrap here. throw tie.InnerException; } finally { // Restore the language mode if (oldLanguageMode.HasValue) { context.LanguageMode = oldLanguageMode.Value; } // Now restore the output pipe... context.ShellFunctionErrorOutputPipe = oldShellFunctionErrorOutputPipe; context.ExternalErrorOutput = oldExternalErrorOutput; // Restore the interactive command state... context.EngineSessionState.CurrentScope.ScopeOrigin = oldScopeOrigin; if (createLocalScope) { context.EngineSessionState.RemoveScope(context.EngineSessionState.CurrentScope); } else if (backupWhenDotting != null) { context.EngineSessionState.CurrentScope.DottedScopes.Pop(); Diagnostics.Assert(backupWhenDotting != null, "when dotting, this dictionary isn't null"); foreach (var pair in backupWhenDotting) { if (pair.Value != null) { context.EngineSessionState.SetVariable(pair.Value, false, CommandOrigin.Internal); } else { context.EngineSessionState.RemoveVariable(pair.Key); } } } // Restore session state... context.EngineSessionState = oldSessionState; } }
internal void InvokeWithPipeImpl(bool createLocalScope, Dictionary<string, ScriptBlock> functionsToDefine, List<PSVariable> variablesToDefine, ErrorHandlingBehavior errorHandlingBehavior, object dollarUnder, object input, object scriptThis, Pipe outputPipe, InvocationInfo invocationInfo, params object[] args) { InvokeWithPipeImpl(ScriptBlockClauseToInvoke.ProcessBlockOnly, createLocalScope, functionsToDefine, variablesToDefine, errorHandlingBehavior, dollarUnder, input, scriptThis, outputPipe, invocationInfo, args); }