2

The OutputType attribute is supposed to give type information through intellisense. However it does not work as expected.

I have tested this in both PSReadline and PowerShell ISE and they work the same.

The following is a sample function I am using:

Function Get-FirstChar
{
    [OutputType([String])]
    [CmdletBinding()]

    param(
      [Parameter(Mandatory=$true, ValueFromPipeline=$true)][string[]]$Strings
    )

    process {
        foreach ($str in $Strings) {
            $str.SubString(0, 1);
        }   
    }
}

When I do:


"John","Simon" | Get-FirstChar | % { $_.<TAB> }

I get the suggestions (regardless of platform):

Equals       GetHashCode  GetType      ToString

However when I do:

("John","Simon" | Get-FirstChar).<TAB>

Then I get all the string methods like SubString etc.

I have also tried a string array String[] as the output type and it still don't work :(

Can someone shed like on how to use OutputType attribute to say that one or more strings will be returned from a powershell function?

Thank you

Tahir Hassan
  • 5,715
  • 6
  • 45
  • 65

1 Answers1

2

Obviously, your expectations are correct. I must say I'm surprised it doesn't work for [string] as it does work for other, complex types:

function Get-ProcessEx {
    [OutputType([System.Diagnostics.Process])]
    param ()
}

Get-ProcessEx | ForEach-Object { $_.}

When I've tried with [string] I get only property (and that is not very helpful for strings, the only property they have is Length). I would consider that a bug, or limitation of the way tools like PowerShell ISE and PSReadline respond to information that objects returned from your functions are strings. E.g. if you try the same with other simple types, result matches the expectations:

function Get-Int {
    [OutputType([int])]
    param ()
}

Get-Int | ForEach-Object { $_. }

It seems to be affecting cmdlets too, I can't get any of existing cmdlets that define same OutputType to provide tab-completion for string's methods:

Get-Command | Where-Object { $_.OutputType.Type -eq [String] }
# Join-Path, not too surprisingly, returns System.String...
Join-Path -Path C:\temp -ChildPath a.txt | ForEach-Object { $_.}

I guess in either case it's worth reporting on PowerShell's UserVoice.

BartekB
  • 8,492
  • 32
  • 33
  • Yes, from my own testing it only affects string output type. I am first going to try it in the latest version of Powershell before reporting it. – Tahir Hassan Dec 27 '16 at 21:02
  • One solution would be to extract the string class's interface and use `Add-Type` and then reference it. From the little testing I have done, if the type you reference does not exist, it doesn't fail, so if you distribute functions with it, it will still work for others. – Tahir Hassan Dec 27 '16 at 21:05
  • I have submitted the issue on GitHub, see https://github.com/PowerShell/PowerShell/issues/2935 (I mentioned that you reproduced the issue) – Tahir Hassan Dec 28 '16 at 00:58
  • OutputType accepts strings so that you can reference types that exist in Extended Type System only (I've blogged about it a while ago: https://becomelotr.wordpress.com/2012/06/17/outputtypewhy-would-you-care/). It's used a lot in CDXML functions, because from .NET point of view all output the same type, just with different WMI class instances (thus different properties/methods available). E.g. (`Get-Command Get-Disk | % OutputType`). It's not very picky. ;) – BartekB Dec 28 '16 at 05:05