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!
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:
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:
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:
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…
Pingback: Episode 192 – Eric Williams from Cisco on the UCS PowerTool « PowerScripting Podcast
Pingback: Tydzień prezentacjami silny… « PowerShell po polsku
Pingback: Event 3: My way… | IT Pro PowerShell experience
Pingback: OutputType(): Optional but Recommended | Adam the Automator
Anyone know how to define the OutputType of a simple .ps1 script?
You can use
same way in the scripts:
It will bring the same ItelliSense/ TabExpansion experience as it does for functions.
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.