protected string RenderScriptValue(PSObject inputObject, ScriptBlock script, bool dontGroupMultipleResults, PsContext context) { // Let the script also use context created by the custom header script (if any). context = context + m_groupByHeaderCtx; Collection <PSObject> results = null; if (null == context) { context = new PsContext(); } if (null == m_pipeIndexPSVar) { m_pipeIndexPSVar = new PipeIndexPSVariable(this); } context.Vars["_"] = new PSVariable("_", inputObject); context.Vars["PSItem"] = new PSVariable("PSItem", inputObject); context.Vars["PipeOutputIndex"] = m_pipeIndexPSVar; PowerShell shell; using (DbgProvider.LeaseShell(out shell)) { #if DEBUG sm_renderScriptCallDepth++; if (sm_renderScriptCallDepth > 10) { // Helps to catch runaway rendering /before/ gobbling tons of memory System.Diagnostics.Debugger.Break(); // Maybe I should just throw? } #endif // // This code is a lot nicer-looking. But the problem with it is that non- // terminating errors get squelched (there's no way for us to get them), // and I'd prefer that no errors get hidden. Strangely, non-terminating // errors do NOT get squelched when calling script.InvokeWithContext // directly in InvokeScriptCommand.InvokeWithContext. I don't know what is // making the difference. I thought it might have something to do with the // SessionState attached to the ScriptBlock, but I couldn't demonstrate // that. // // Things to try with both methods: // // $ctx = $null // $savedCtx = $null // Invoke-Script -ScriptBlock { "hi" ; Write-Error "non-term" ; "bye" } -WithContext $ctx // // { "hi" ; Write-Error "non-term" ; "bye" }.InvokeWithContext( @{}, @() ) // // $tmpMod = New-Module { } // $scriptBlockWithDifferentExecCtx = & $tmpMod { { "hi" ; Write-Error "non-term" ; "bye" } } // $scriptBlockWithDifferentExecCtx.InvokeWithContext( @{}, @() ) // // Register-AltTypeFormatEntries { New-AltTypeFormatEntry -TypeName 'System.Int32' { New-AltCustomViewDefinition { "It's an int: $_" ; Write-Error "this is non-terminating" ; "done" } } } // 42 // // try // { // // Note that StrictMode will be enforced for value converters, because // // they execute in the scope of Debugger.Formatting.psm1, which sets // // StrictMode. // results = script.InvokeWithContext( context.Funcs, context.VarList ); // } // catch( RuntimeException e ) // { // return new ColorString( ConsoleColor.Red, // Util.Sprintf( "<Error: {0}>", e ) ) // .ToString( DbgProvider.HostSupportsColor ); // } shell.AddScript(@"$args[ 0 ].InvokeWithContext( $args[ 1 ].Funcs, $args[ 1 ].VarList )", true) .AddArgument(script) .AddArgument(context); results = shell.Invoke(); // Let's not keep the input object rooted. context.Vars.Remove("_"); context.Vars.Remove("PSItem"); #if DEBUG sm_renderScriptCallDepth--; #endif // For some reason, sometimes shell.HadErrors returns true when // shell.Streams.Error.Count is 0, when the pipeline is stopping. if (Stopping) { return(String.Empty); } // INT2d518c4b: shell.HadErrors is clueless. //if( shell.HadErrors ) if (shell.Streams.Error.Count > 0) { if (1 == shell.Streams.Error.Count) { return(new ColorString(ConsoleColor.Red, Util.Sprintf("<Error: {0}>", shell.Streams.Error[0])) .ToString(DbgProvider.HostSupportsColor)); } else { return(new ColorString(ConsoleColor.Red, Util.Sprintf("<Multiple errors ({0}) encountered>", shell.Streams.Error.Count)) .ToString(DbgProvider.HostSupportsColor)); } } else { if ((null == results) || (0 == results.Count)) { return(null); } return(ObjectsToMarkedUpString(results, "{0}", // <-- IMPORTANT: this prevents infinite recursion via Format-AltSingleLine null, dontGroupMultipleResults).ToString()); } // end else( no errors ) } // end using( shell lease ) } // end RenderScriptValue()