コード例 #1
0
        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()