Enabling tab completion for the properties of a custom object

Welcome Forums General PowerShell Q&A Enabling tab completion for the properties of a custom object

This topic contains 4 replies, has 3 voices, and was last updated by

 
Participant
1 year, 9 months ago.

  • Author
    Posts
  • #65803

    Participant
    Points: 1
    Rank: Member

    Although I'm not new to PowerShell, I am new to working with modules. In creating my first module, I am trying to get tab completion to work with the properties contained in one of the functions.

    Example: Get-MyFunction | Select-Object MyOb[tab key] should result in Get-MyFunctin | Select-Object MyObjectProperty

    In the function, I am creating an array to hold data from the pscustomobject. It is the array that is returned by the function.

    [System.Collections.ArrayList]$arrMyArray = @()

    Next, I loop through the relevant information, adding them to a pscustomobject:

    $MyObject = [PSCustomObject]@{
    			MyObjectProperty = $strValue1
    			MyOtherObjectProperty = $strValue2
    

    It is these properties that I want to enable tab completion.

    At the end of each loop, I add the information to the array object:

    $arrMyArray.Add($MyObject) | Out-Null

    Once all loops are completed, I return the the array:

    Return $arrMyArray

    Following the information in this post, I was able to get it to work, but even adding this code within my function will cause the properties to appear in the tab completion of all functions in the module that have an OutputType of 'array'.

    Any help or suggestions will be greatly appreciated.

  • #65805

    Moderator
    Points: 24
    Team Member
    Rank: Member

    You'll need to roll your own class to get tab completion on properties.

    Example (PowerShell v5 and later)

    class ForumItemData {
        [String] $Name
        [String] $Status
    }
    
    function Get-ItemData {
    
        [CmdletBinding()]
        [OutputType('ForumItemData')]
        param ()
    
        $obj = [ForumItemData]::new()
        $obj.Name = 'Testing 123'
        $obj.Status = 'Active'
        $obj
    }
    
    Get-ItemData | Select-Object -Property Name, Status
    

    Example (PowerShell v4 and earlier)

    Add-Type -TypeDefinition @'
    using System;
    
    namespace PowerShellOrg.Forum
    {
        public class ItemData
        {
            public string Name { get; set; }
            public string Status { get; set; }
        }
    }
    '@ -ErrorAction SilentlyContinue
    
    function Get-ItemData {
    
        [CmdletBinding()]
        [OutputType('PowerShellOrg.Forum.ItemData')]
        param ()
    
        $obj = New-Object -TypeName 'PowerShellOrg.Forum.ItemData'
        $obj.Name = 'Testing 123'
        $obj.Status = 'Active'
        $obj
    }
    
    Get-ItemData | Select-Object -Property Name, Status
    
    • #65844

      Participant
      Points: 1
      Rank: Member

      Daniel,

      Thanks for the quick and thorough response. I will definitely incorporate this into my script.

  • #65806

    Keymaster
    Points: 1,704
    Helping HandTeam Member
    Rank: Community Hero

    This is hard to do in a script.

    .NET uses Reflection to figure out what members a type has; in your case, your type is a PSCustomObject, which does not have any members. At least, none defined in its base, which is all .NET can use.

    For one, you're building your function very contrary to PowerShell patterns in terms of accumulating objects in an array. This blocks the pipeline, which is a Bad Thing. See https://devopscollective.gitbooks.io/the-big-book-of-powershell-gotchas/content/manuscript/accumulating-output-in-a-function.html. The Return keyword is misleading, and in a function you probably should avoid it. In a function, it's an alias to Write-Output, which is preferred. Continually adding objects to an array is also a decent performance hit as the array grows.

    What you'd need to do, in order for this to work correctly, is register a type (e.g., Add-Type) that has the members you want, and then output objects of that type, and then modify your function declaration to indicate it was outputting objects of that type. It's honestly a lot of work, and it's kind of overkill in terms of a "script cmdlet." You should also be outputting objects one at a time to the pipeline so that PowerShell can stream objects instead of dealing with giant collections.

    • #65845

      Participant
      Points: 1
      Rank: Member

      Thanks Don. It appears I have a lot more homework to do. Thanks for the feedback and tips.

The topic ‘Enabling tab completion for the properties of a custom object’ is closed to new replies.