Powershell again. Pipes, and "This is not an output"

My experiences with PowerShell continue and every so often realize that I never really understood something I thought I'd "got" some while back

I've spent most of my time trying not to use the WRITE cmdlets to send output to the screen. After all if I want to write "Hello, World" to the screen I can have a function

function hw
  { 'Hello, World' }

No need for a Print, Write, Echo or any other command: in PowerShell an output with nowhere else to go ends up on the screen. If I want formatted output  FORMAT-LIST and FORMAT-TABLE do a great job, especially since I "discovered" calculated fields. Since I always used to get my queries in Access to do loads of work, shoving the work onto FORMAT-TABLE seems natural enough, even if the syntax is little weird. The field is actually written as a hash table @{ label="Text", Expression={some code}    }. Of course "Some code" can do anything you want and what it returns goes in the table. So I had a bright idea over the weekend. I can have a menu using format-table. Here the code

Function Choose-Process
Format-Table -inputobject $Proc @{ Label = "ID"; Expression={($global:counter++) }} , processName
$proc[(read-host "Which one ?")]

So I set a counter, get a list of processes, and then format a table, in formatting the table I output and increment the counter; the I ask the user to input a number to choose one and that gives me the offset into the array of processes of the one to return. When I run it here's what I get:

PS C:\Users\Jamesone> choose-proc

ID ProcessName
-- -----------
0 audiodg
1 CcmExec

Which one ?: 1

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
744 29 13128 10560 92 2204 CcmExec


Of course I  want to save this. So I type in $proc=choose-proc and I get

Which one ?:

What the ... ? Where did my menu go ? And the answer is: the menu was OUTPUT. Where did I tell PowerShell that  format-table wasn't to go to standard output but $proc[offset] was ? I didn't so both ended up being stored in the result.

Anyone who's explored PowerShell's providers will have found there is one for variables. Now I get it ... $varName= MyFunction is actually MyFunction > Variable:varName. This behaviour can work for or against you depending on the situation, and here I have to use a for loop and use WRITE-HOST to force output to go the screen [Update: no I don't need to. See Jeffrey's comment below]

I guess I was still thinking in Basic, where the last line of your function usually returns the result.  PowerShell's Outputs are different, they go down the "Standard Output" pipe unless told otherwise and standard output ends up on the screen if the "end of pipe" is left Open; just like you'd expect from a Shell.   And since I was quoting my university lecturers a little while ago here's something which was written on the board in our first programming class.

It is practically impossible to teach good programming style to students that have had prior exposure to BASIC; as potential programmers they are mentally mutilated beyond hope of regeneration.
Edsger Dijkstra )

Technorati tags: ,

Comments (10)
  1. Anonymous says:

    I mentioned my weekend of PowerShell , and that I’ve been working on scripts for the Office Communications

  2. Anonymous says:

    I’ve been showing PowerShell on the roadshow, and Steve warning me about it becoming the "Look-how-clever-I-am-with-PowerShell

  3. Anonymous says:

    [link] Marco

  4. Anonymous says:

    Let's face it, PowerShell does a bunch of magic for you. If we've done our job right, this magic

  5. James ONeill says:

    Jeffrey, thanks for your comments and your kind words over on the Powershell team blog.

    Matt. The function would now go

    Function choose-process



    Format-Table -autosize -inputobject $Proc @{ Label = “ID”; Expression={($global:counter++) }} , processName | out-host

    $proc[ [int[]](Read-Host “Which ones? “).Split(“,”)] }

    note: I’ve revised this comment to included Jeffery’s multi-select – since I’ve just written something which actually uses it 🙂

  6. James ONeill says:

    Fantastic Hecks. thanks for sharing.

  7. Jeffrey Snover says:

    I don’t think you need a FOR loop to fix this, the OUT-HOST should suffice.  Just do

    Format-Table <blah blah> | Out-Host ;

    And you’ll be all set.  By the way, when I ran this on my machine, I decided to add -AutoSize to the Format-Table – that is much nicer to deal with.


    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

  8. Jeffrey Snover says:

    BTW – if you wanted to allow multiple processes to be chosen you could do this:

    $proc[ [int[]](Read-Host "Which ones? ").Split(",")]

    See if you like that.

    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

  9. Matt Wilson says:

    This is really cool!  I’ve been wanting something like this for a while, but just haven’t thought it out yet.

    After reviewing all the comments & having more time to think about it, do you have a "better version" written now that you can share with us?  


  10. Hecks says:

    I have a set of such functions that basically do the equivalent of SHIFT/CTRL selecting from a list with a mouse.  The trick works with just about any Powershell output really.  Here’s one for selecting directory items:


    ## Pick-ChildItem.ps1 ##

    param ($path, [array]$index, [switch]$force)

    if ($force) {$switch = "-force"}

    $global:items = (invoke-expression "get-childitem ‘$path*’ $switch" |

      sort-object  @{expression={$_.PSIsContainer}; Descending=$true},

      @{expression={$_.Name}; Ascending=$true})

    if ($index -ne $null) {

      $index | %{$_} | %{$items[$_ – 1]}


    else {$items | %{$i=1}{$_; $i++} |

      format-table @{label="ID"; expression={$i}}, Name,

      @{label="Path"; expression={

        if ($_.PSISContainer) {"<Dir> $_"}

        else {$_.directoryname}}} -auto




    new-alias -name pci -value c:ScriptsPick-ChildItem.ps1

    pci . <- returns all items in current directory

    pci . 4 <- returns fourth item in list

    pci . (1..6),(47..50) <- returns all items in ID ranges

Comments are closed.

Skip to main content