Text Output Is Not a Contract

Text Output Is Not a Contract

  • Comments 5

In PS V1, this is what you get for GET-COMMAND -SYNTAX

PS> Get-Command Get-Process -Syntax
Get-Process [[-Name] <String[]>] [-ComputerName <String[]>] [-Module] [-FileVersionInfo] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Get-Process -Id <Int32[]> [-ComputerName <String[]>] [-Module] [-FileVersionInfo] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Get-Process [-ComputerName <String[]>] [-Module] [-FileVersionInfo] -InputObject <Process[]> [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]

I look at that and a little bit of vomit comes up into my mouth.  I've been experimenting with my own radically different version but that probably won't ship in V2 and we'd like V2 to be better.  I mentioned that if we just put a newline between the parametersets and got rid of the ubiquitous parameters - we would be TONS ahead.  This is what it would look like:

PS> Get-Command Get-Process -Syntax
Get-Process [[-Name] <String[]>] [-ComputerName <String[]>] [-Module] [-FileVersionInfo]

Get-Process -Id <Int32[]> [-ComputerName <String[]>] [-Module] [-FileVersionInfo]

Get-Process [-ComputerName <String[]>] [-Module] [-FileVersionInfo] -InputObject <Process[]>

MUCH better right?  As we discussed this, someone pointed out that this change would break any scripts that parsed the text output for the V1 version.  At first I looked at the person as though they had a rat's tail hanging out of their mouth (thinking - Get-Command gives you a structured object - why would you render it to text and then parse it?!!!).  Then I realized that we hadn't actually stated what I think is obvious so now I'll state it:

In PowerShell - TEXT OUTPUT IS NOT A CONTRACT.

In UNIX, text output is effectively a programming contract because that is what the whole system is built upon.  One command outputs text and other programs know what to expect so they parse the text to get the appropriate data elements so that they can code against it.  In this model, if you change the text output of a command - you run the risk of breaking a bunch of scripts.  In reality, this happens.  It doesn't happen often because the commands don't change that much.  The other reality is that admins cope.  That's what admins do - they deal with the world as it is not as it should be.  "Unix commands shouldn't change their outout because they break my scripts, they do, my scripts are broken, grrrrrrr - cope."  It's a dirty business but someone has to do it.  :-)

That is the world of TEXT parsing.  In PowerShell - we provide an object-based world where you don't have to parse the text to get the properties that you want - you just ask for property and you get it - no fuss, no muss.  Given that - in Powershell TEXT OUTPUT IS NOT A CONTRACT.  Said aother way -
We reserve the right to radically change our text rendering to improve our customer experience. 
(God knows we have some improvements to make. :-) )

Clever people will point out that we can change our text output and not break scripts as long as they are PowerShell scripts and not say a PERL script that invokes PowerShell and parses its output.  That is exactly correct and exactly why I'm blogging this now so that everyone is put on notice and can code accordingly. 

I imagine that some people will howl about us doing our Perl buddies wrong but the reality is that this is not an issue as long as we are clear about the rules and people can adjust.  In reality, we probably don't even need to do that.  

1) If you go the National Bureau of Standards in Denver and open up the closet marked "COPER", you'll find a System Admin clutching a PERL manual.  (I'm serious, these guys do an awesome job given the world we've created for them.)
2) These guys are going to invoke PowerShell in a way that it outputs text that is easy to parse.  They are going to render it to CSVs or XML or some other useful format which is SUPER easy to do in PowerShell and avoids a bunch of horrible parsing.

As I say, it is pretty obvious when you think about it for a couple minutes but I felt it was important for us to be explicit about it so there is no confusion downstream (well ... less confusion).

Cheers.

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

 

Leave a Comment
  • Please add 8 and 7 and type the answer here:
  • Post
  • Your own scripts shouldn't output text as a contract, either - for many of the same reasons, and because PowerShell (being object-oriented) will do a lot of work with you if you aren't sitting around munging text. See http://concentratedtech.com/content/?p=139 - have your scripts output objects.

  • nice idea, but you are taking objects then returning an array of strings to the pipeline.. sure it looks pretty , but its not useful.. either write-host text, or present useful objects.

  • I've been using a script which expands this sort of thing out for a long time now. Check out this output:

    § ATLLAPHROTTENBE {~} Get-Parameter Get-Command | ft -autosize

    Name         Type         ParameterSet  IsMandatory Pipeline

    ----         ----         ------------  ----------- --------

    Verb         String[]     CmdletSet           False    False

    Noun         String[]     CmdletSet           False    False

    PSSnapin     String[]     CmdletSet           False    False

    TotalCount   Int32        CmdletSet           False    False

    Syntax       Boolean      CmdletSet           False    False

    ArgumentList Object[]     CmdletSet           False    False

    Name         String[]     AllCommandSet       False     True

    CommandType  CommandTypes AllCommandSet       False    False

    TotalCount   Int32        AllCommandSet       False    False

    Syntax       Boolean      AllCommandSet       False    False

    ArgumentList Object[]     AllCommandSet       False    False

    You can find the latest version of this script on PoshCode: http://poshcode.org/?lang=&q=get-parameter

  • The problem with Powershell over Perl is bad performance when dealing with 100,000+ objects. Dealing with 100,000+ text lines is a lot faster in Perl/Bash or whatever. So I would have to say Yes you have many improvements to make! (Otherwise very useful for tasks requiring smaller data sets)

    "We reserve the right to radically change our text rendering to improve our customer experience. (God knows we have some improvements to make. :-) )"

  • @Blair.

    We are doing quite a bit of work on perf in V2 particularly for startup times and text parsing.  Don't give up on us and try it again when we have V2 out.  You'll see some improvements in our CTP3 out later this year.

    jps

Page 1 of 1 (5 items)