OutputType–why would you care?

WMF 3.0 RC is awesome. It was great in CTPs, even better in beta, but it improves with each following version. One of my favourite additions in RC depends on thing that existed in PowerShell 2, but it was ignored because we could not see any value in it.

The reason for that was simple: it was just a metadata. Unless you would look closely at any command, including self-defined functions, you would never notice it’s there. It changes with version 3. Now knowing in advance what command will output can give authoring tools and hosts ability to act on this information.

Looking behind in the pipeline.

Have you ever wished that you could tab-complete things in pipeline? Wouldn’t it be great if PowerShell would actually recognize things that happen in previous step and give as clues based on that information? Well, in RC it actually works. And depends on OutputType defined by a given command.

As a result, typing code like this one:

Get-ChildItem | Where-Object { $_.N

…would allow me to press [Tab] after N and get Name. Same applies also to simplified syntax and other –Object cmdlets. But wait, there’s more! Uśmiech

If you would use the same technique together with passing scriptblock to parameters that take pipeline input by property name – you get the same experience. So also here:

Get-ChildItem | Rename-Item -NewName { $_.N

… I could do the same.

Intellisense in ISE – even better…

When you were writing long script in PowerShell ISE in version 2 you were often tempted to run it partially so that [Tab] would complete variable names/ properties. In new ISE we got Intellisense and this fact alone was very cool. But it got even better now. First of all – we can complete names of variables we define even if we do not run actual code. But OutputType kicks in also here. If we define variable as a result of command(s) that exposes OutputType – our variable name will completed, but also all properties and methods that OutputType has will be completed/ suggested:

Intellisense-OutputType

As you can see now you can save a lot of time during authoring your scripts and modules. There is only this small requirement – OutputType.

My command has OutputType, and yours?

You would think it’s hard to get it? As is often the case in PowerShell scripting this is easier than you would imagine. Remember: OutputType is not a magic, it’s just metadata your command will expose to outside world. In other words: it won’t check for actual output type. All you need to do is specify it in the same place where you make sure your function is advanced with [CmdletBinding()] attribute:

function Test-Output {

[OutputType(‘System.String’)]

param ($Name)

    “Hello, $Name!”

}

And we will get same experience – even without defining this function – intellisense will pick it up:

IntellisenseMyFunction

And we can also do the same for pseudo-types that exist only in ETS. How? First we need to define type with some methods/ properties:

$Common = @{

    MemberType = ‘NoteProperty’

    TypeName = ‘Foo.Bar’

    Value = $null

}

 

Update-TypeData @Common -MemberName Alfa

Update-TypeData @Common -MemberName Beta

Update-TypeData @Common -MemberName Gamma

 

function Test-MyType {

[OutputType(‘Foo.Bar’)]

param ()

    [PSCustomObject]@{

        Alfa = 1

        Beta = 2

        Gamma = 3

    }

}

Will it work? As you can see my metadata is sort of cheating – I’m not doing anything to “mark” output as my pseudo-type Foo.Bar. But as I said before – it’s only this metadata that PowerShell will take a look at:

MyType-PsuedoOutputType

So – with very little work  I was able to simplify using my command and it’s results for anybody who will decide to do so.

Action points.

There actually two. First of all – remember: from now on you should add this attribute to your functions. It’s really not hard to do that, and it will make experience better for anybody who will decide to use those functions, including yourself. If you want to read more about it, or want to take it to the next level (e.g. define different OutputType for different ParameterSets) you can find more information in help: about_Functions_OutputTypeAttribute

Second: require this feature. If you have influence on cmdlet/ modules authors and you see it’s missing – convince them to add it for your and others profits. And with that I would like to ask you to click on this link on connect and vote up suggestion related to it. Reason for that is simple: lots of commands that you will find today or that will ship with Windows Server 2012 do not have this metadata set. Obviously, adding it to compiled code is slightly different but still does not require very much work… So if anybody want to make our life easier – now he can. In my opinion it’s no-brainer. Result’s type picked up in advance by your pipelines and ISE (almost) for free…

Advertisements

8 thoughts on “OutputType–why would you care?

  1. Pingback: Episode 192 – Eric Williams from Cisco on the UCS PowerTool « PowerScripting Podcast

  2. Pingback: Tydzień prezentacjami silny… « PowerShell po polsku

  3. Pingback: Event 3: My way… | IT Pro PowerShell experience

  4. Pingback: OutputType(): Optional but Recommended | Adam the Automator

    • You can use

      OutputType

      same way in the scripts:

      Set-Content -Force -Path C:\Windows\Temp\Get-String.ps1 -Value @'
      [OutputType([System.String])]
      param ()
      '@
      
      (Get-Command C:\Windows\Temp\Get-String.ps1).OutputType.Type.FullName
      
      System.String
      

      It will bring the same ItelliSense/ TabExpansion experience as it does for functions.

  5. This was a big help to me; thanks. How would you implement this for different functions contained in a PowerShell module, where each function has different properties?

    • OutputType is a command attribute, so each function in your module needs to define it separately. So even if your functions would share these – you need to copy&paste your code to each of them.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s