PowerShell Remoting Project Home

Thursday, June 22, 2006

Enter Nested Prompt function

In windows PowerShell, $Host object provides direct access to some important APIs. One of the interesting functions is $Host.EnterNestedPrompt(). Frankly speaking, it did not appeal to me at all when I first tried it. But I discovered this beauty after I implemented my own PSHost  in PowerShell Remoting,

What did it do?
  1. Suspend & Save current execution context state.
  2. Create a new nested execution context.(Nested pipline, new prompt execution helper and new script excution helper)
  3. Push the new nested execution context to stack. (PowerShell use a static stack. In my PowerShell Remoting, it is more complicate. Every client has its own host; every host has its own stack for nested prompt.)
  4. Increase $NESTEDPROMPTLEVEL
That is to say:
  1. Your current pipeline is suspended. All variables and errors state were saved.
  2. In the meantime, you still have access to monad engine. You can have new prompt, run new script or other interactive command.
  3. When you are done with the new scope, you can call invoke $Host.ExitNestedPrompt()  or "exit" (which will call $Host.ExitNestedPrompt())  to return to previous pipeline.
What can I do with it?
  1. First, Let's see how "Suspend" works when using -confirm option or "Set-PSDebug -Step"
  2. > kill 2804 -Confirm

    Confirm
    Are you sure you want to perform this action?
    Performing operation "Stop-Process" on Target "Notepad (2804)".
    [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help
    (default is "Y"):

    > Set-PSDebug -Step
    > D:\ps1\special.ps1

    Continue with this operation?
       1+ D:\ps1\special.ps1
    [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help
    (default is "Y"):
    When you choose [S]Suspend, you actually called $Host.EnterNestedPrompt() which break current script and provide you an nested prompt.
  3. Secondly, $Host.EnterNestedPrompt() can be used as break point when debugging your script.
  4. To make a break point, you can add $Host.EnterNestedPrompt() at anywhere in your script. When your script execute to it, you will have a nested prompt to explore variables and errors at this break point.
    > 1..10 | %{if($_ -eq 5) {$host.EnterNestedPrompt()};$_}
    1
    2
    3
    4
    >>> $_
    5
    >>> exit
    5
    6
    7
    8
    9
    10
Be careful
  1. Nested prompt and original prompt share same variables provider. So when you change a variable in nested prompt, the change will remain effective in original prompt.
  2. Comannd will be written in history when it is completed. So a suspended command will not be found in history.
  3. The maximum depth of nested prompt level ($NESTEDPROMPTLEVEL) is 128. So always check $NESTEDPROMPTLEVEL for current nested prompt level. You can write it into your prompt function.
  4. Do not try to make a nested function using $Host.EnterNestedPrompt(). But you can always do this.
  5. function factorial
    {
        param ([int]$n = 1)
        if ($n -le 0)
        {
            "Invalid parameter."
             return
        }
        if ($n -eq 1)
        {
            return 1
        }
        return $n * (factorial ($n-1))
    }
Reference: Start-NewScope

Tags:       


Comments:
Great stuff there, Tony!

I have never realized that suspending current cmdlet operation would result in calling nested prompt(although i do show nested prompt level in my "prompt"...)

And also, being able to use Nested Prompt for debugging (since you have mentioned that in the nested level, all of the parent's variables are "saved"...
 

Post a Comment





<< Home