Push-Noun

Push-Noun

  • Comments 5

We looked at a lot of CLI models when designing PowerShell.  One of them was netsh.  One of the things I had a love/hate relationship with was netsh's use of context.  In netsh, you can set context via navigation and then you don't need to provide that context on the command line.  For instance you navigate into the FIREWALL and then you perform a set of operations and you don't need to say that you are working on the firewall because it picks it up from the context.

I thought I would experiment with this a little this morning.  I don't know if this is useful or not but it shows a couple of interesting scripting techniques so I thought I would share it anyway.  This is PUSH-NOUN.PS1.  You can push a NOUN context and then you don't need to specify that noun for the first command in a command sequence - you just specify the verb.  You type "?" for help,  "exit" to exit and "! cmd" to escape and execute a command directly.  The examples will make it more clear. 

First the code:

# Push-Noun.ps1
# Sets a context which allows you to work on a noun similar to the way NETSH does
# WORKS WITH V1

param($noun)
while ($true)
{
    Write-Host "[$Noun]> " -NoNewLine
    $line = $host.UI.ReadLine().trim()
    switch ($line)
    {
    "exit"   {return}
    "quit"   {return}
    "?"      {Get-Command "*-$Noun" |ft Verb,Definition -Auto |out-host}
    {$_.StartsWith("!")}
             {
                $Cmd = $_.SubString(1)
                Invoke-Expression $cmd |out-host
             }
    default  {
                $Verb,$args = $Line.Split()
                $Cmd = "$verb-$Noun $args"
                Invoke-Expression $cmd |out-host
             }
    }
}

Now let's run it:


PS> .\push-noun service
[service]> ?

Verb    Definition
----    ----------
Get     Get-Service [[-Name] <String[]>] [-ComputerName <String[]>] [-Include <String
New     New-Service [-Name] <String> [-BinaryPathName] <String> [-DisplayName <String
Restart Restart-Service [-Name] <String[]> [-Force] [-PassThru] [-Include <String[]>]
Resume  Resume-Service [-Name] <String[]> [-PassThru] [-Include <String[]>] [-Exclude
Set     Set-Service [-Name] <String> [-DisplayName <String>] [-Description <String>]
Start   Start-Service [-Name] <String[]> [-PassThru] [-Include <String[]>] [-Exclude
Stop    Stop-Service [-Name] <String[]> [-Force] [-PassThru] [-Include <String[]>]
Suspend Suspend-Service [-Name] <String[]> [-PassThru] [-Include <String[]>]


[service]> get a*

Status   Name               DisplayName
------   ----               -----------
Running  AeLookupSvc        Application Experience
Running  ALG                Application Layer Gateway Service
Stopped  Appinfo            Application Information
Running  AppMgmt            Application Management
Running  AudioEndpointBu... Windows Audio Endpoint Builder
Running  Audiosrv           Windows Audio


[service]> get |where {$_.name -match "^A" -AND $_.Status -eq "stopped"}
Status   Name               DisplayName
------   ----               -----------
Stopped  Appinfo            Application Information


[service]> !gps *ss

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    673       8     2308       6636    70     6.75    492 csrss
    539       7    16044      21460   190   149.98    540 csrss
   1633      16    11040      17680    68    67.47    656 lsass
    866       5     3976       5720    33     2.56    548 psxss
     33       1      312        760     5     0.08    428 smss


[service]> exit
PS>

Note that given the mechanisms we have, this only really works with the first command in the sequence.  Image that you wanted to do something like:

PS> Get | where {$_.name -match $test} |STOP

Where STOP did not have to specify the NOUN.  You really can't do that today.  We have been thinking about exposing a TOKEN-NOT-RESOLVED event which would call a user-defined function which would allow you to do runtime fixups.  If we had that mechanism in place, you could do this.   Hmmmmmm.

Enjoy!

Jeffrey Snover [MSFT]
Windows Management Partner Architect
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Attachment: push-noun.ps1
Leave a Comment
  • Please add 3 and 5 and type the answer here:
  • Post
  • Great post.  It's amazing how so small a script could accomplish so much.  The techniques shown even open the door to create customized shell prompts.

  • > " We have been thinking about exposing a TOKEN-NOT-RESOLVED event which would call a user-defined function which would allow you to do runtime fixups.  If we had that mechanism in place, you could do this.   Hmmmmmm.

    "

    Hmmmmmm.  Interesting idea, but on balance I'd say no thanks.  NetSh is a much more specific environment (and I would agree about the love/hate thing on the way it works).  I'd add that if you guys are busy there might be better things to focus on:-)

    Chris

  • Hey Jeffrey,

    That's great news - I had mentioned that to you guys before, but in the context of a comparison to Tcl's "unknown" proc, and I'm delighted to hear you're seriously considering it. I think that's a great idea - it would really open up Posh for the most insane extensions and mix-ups.

    Cool!

    - Oisin

  • one of the things that drew me to powershell was how easy and NATURAL. it was to extend it as a LANGUAGE, and build DSLs. Though this is just an example, its still a great example of that in a different context

  • Hi,

    I've long been looking for something like this! Thank you!

    Btw. have there been any developments on this part recently? some new technique or something?

    Kind regards,

    Vladan

Page 1 of 1 (5 items)