Skip to content

PSUseOutputTypeCorrectly generates false warning for PSObjects with custom ETS type names #195

Closed

Description

@KirkMunro

I have many functions that generate PSObjects. Whenever I create a PSObject, I add a type name to it. This is done either by invoking .PSTypeNames.Add(...), .PSTypeNames.Insert(...), or if I'm creating the object using [pscustomobject]@{...} then I just apply a PSTypeName value to the hashtable with the custom name for the object I am creating.

In scenarios like these, PSUseOutputTypeCorrectly identifies that I'm returning a PSObject and then complains because my OutputType is a string, set to the actual PSTypeName of the object that is returned. I'm following the best practice, but PSScriptAnalyzer is incorrectly assuming I'm doing the wrong thing. The PSUseOutputTypeCorrectly rule should not generate a warning on functions that return PSObjects when the OutputType is set to a string (the ETS type name for those PSObjects).

Activity

  1. KirkMunro commented on May 22, 2015

    @KirkMunro
    ContributorAuthor

    I just found another scenario where this occurs. I have a command that returns an array of PSObjects. This warning indicates that my command returns an object of type System.Object[], but that type is not declared in the OutputType attribute. My OutputType properly identifies the ETS type name here as well, as a single quoted string. Please make sure this is addressed for collections as well.

  2. quoctruong commented on Jun 1, 2015

    @quoctruong

    Hi Kirk. Thanks for identifying the bugs. Do you mind sharing a snippet of the code for this bug?

  3. KirkMunro commented on Jun 1, 2015

    @KirkMunro
    ContributorAuthor

    Sure thing. Here you go:

    function Test-EtsOutputTypeSingular {
        [CmdletBinding()]
        [OutputType('MyCustom.OutputType')]
        param()
        [pscustomobject]@{
            PSTypeName = 'MyCustom.OutputType'
            Prop1 = 'SomeValue'
            Prop2 = 'OtherValue'
        }
    }
    
    function Test-EtsOutputTypeCollection {
        [CmdletBinding()]
        [OutputType('MyCustom.OutputType')]
        param()
        @(
            [pscustomobject]@{
                PSTypeName = 'MyCustom.OutputType'
                Prop1 = 'SomeValue'
                Prop2 = 'OtherValue'
            }
            [pscustomobject]@{
                PSTypeName = 'MyCustom.OutputType'
                Prop1 = 'AnotherValue'
                Prop2 = 'LastValue'
            }
        )
    }
    

    Drop that into a file, save it, and run Invoke-ScriptAnalyzer against it and you'll see the false positives. This rule needs to allow for custom ETS type names in the OutputType attribute, which are defined as string since they are not actually instances of System.Type.

  4. quoctruong commented on Jun 3, 2015

    @quoctruong

    So does this case only apply to PSCustomObject with the property PSTypeName? Are there any other similar cases as well?

  5. KirkMunro commented on Jun 3, 2015

    @KirkMunro
    ContributorAuthor

    Yes, it seems so. Here are two more cases where it is working as expected and not generating false positives (whether intentional or not):

    function Test-EtsOutputTypeSelected {
        [CmdletBinding()]
        [OutputType('MyCustom.OutputType')]
        param()
        $s = Get-Service wuauserv | Select-Object -Property Name,DisplayName,Status
        $s.PSObject.TypeNames.Insert(0,'MyCustom.OutputType')
        $s
    }
    
    function Test-EtsOutputTypeNew {
        [CmdletBinding()]
        [OutputType('MyCustom.OutputType')]
        param()
        $o = New-Object -TypeName System.Management.Automation.PSObject -Property @{
            OneFish = 'Two fish'
            RedFish = 'Blue fish'
        }
        $o.PSObject.TypeNames.Clear()
        $o.PSObject.TypeNames.Add('MyCustom.OutputType')
        $o
    }
    

    Based on those results, it seems this is specific to when PSTypeName is used to define the custom type name.

  6. quoctruong commented on Jun 3, 2015

    @quoctruong

    In these cases, it doesn't generate warning because the VariableAnalysis was not able to detect the type of the value returned.

  7. KirkMunro commented on Jun 3, 2015

    @KirkMunro
    ContributorAuthor

    How about this one?

    function Test-EtsOutputTypeNew2 {
        [CmdletBinding()]
        [OutputType('MyCustom.OutputType')]
        param()
        New-Object -TypeName System.Management.Automation.PSObject -Property @{
            PSTypeName = 'MyCustom.OutputType'
            OneFish = 'Two fish'
            RedFish = 'Blue fish'
        }
    }
    

    The type of that object should be identifiable, so is it properly checking the type and giving it a green light or failing to detect the type?

  8. quoctruong commented on Jun 3, 2015

    @quoctruong

    So I just checked and it doesn't get the type in this case because for some reason, System.Type.GetType("System.Management.Automation.PSObject") returns null (really weird).

  9. quoctruong commented on Jun 15, 2015

    @quoctruong

    Closed with #243

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions