protected string RenderScriptValue(PSObject inputObject, ScriptBlock script, bool dontGroupMultipleResults) { // Let the script also use context created by the custom header script (if any). if (m_preservedScriptContext != null) { script = m_preservedScriptContext.NewBoundScriptBlock(script); } #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 using (DbgProvider.LeaseShell(out PowerShell shell)) { // // script.InvokeWithContext is a lot nicer-looking. But the problem with // it is that non-terminating errors don't go to the output or an easily // checked buffer, and I'd prefer that no errors get hidden. Strangely, // calling script.InvokeWithContext directly in // InvokeScriptCommand.InvokeWithContext does send the errors down the // pipeline to be displayed. I don't know what is making the difference. // // 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 // Collection <PSObject> results; try { // Note that StrictMode will be enforced for value converters, because // they execute in the scope of Debugger.Formatting.psm1, which sets // StrictMode. InvokeCommand.InvokeScript(false, sm_pipeIndexScript, null, m_pipeIndex); var info = InvokeCommand.GetCmdlet("ForEach-Object"); shell.AddCommand(info).AddParameter("Process", script); results = shell.Invoke(new[] { inputObject }); } catch (RuntimeException e) { // Make the error available for inspection: AddToError(Util.FixErrorRecord(e.ErrorRecord, e)); return(new ColorString(ConsoleColor.Red, Util.Sprintf("<Error: {0}>", e)) .ToString(DbgProvider.HostSupportsColor)); } #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) { // (don't need to call AddToError explicitly; they will already be // available in $error) 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()