Out-GridView with Custom Columns

by Dec 27, 2021

Out-GridView can be a universal dialog when you use the -OutputMode or -PassThru parameters. When you do, a grid view window displays additional buttons in its lower right corner so you can choose items and pass them on to additional cmdlets.

This line could help picking a service to stop, for example:

Get-Service | Where-Object CanStop | Out-GridView -Title 'Service to stop?' -OutputMode Single | Stop-Service -WhatIf 

However, Out-GridView offers no control over the properties it displays. In the example above, the user really just needs to see the service name and possibly its dependent services.

Of course, you could use Select-Object to select the properties to display. Now the grid view window would show exactly the columns you asked for, but since you permanently removed all other properties and changed the object type, subsequent cmdlets might stop working as expected:

Get-Service | Where-Object CanStop | Select-Object -Property DisplayName, DependentServices | Out-GridView -Title 'Service to stop?' -OutputMode Single | Stop-Service -WhatIf 

When you run the line above, the grid view window now looks great, but Stop-Service would no longer stop the service you selected since Select-Object changed the object type from service to a custom object:

 
Stop-Service : The specified wildcard character pattern is not valid: @{DisplayName=Windows Audio Endpoint Builder; 
DependentServices=System.ServiceProcess.ServiceController[]}   
 

In the previous tip we already used a hidden technology you can use to tell Out-GridView which columns it should show – without removing any property or changing object types:

# create object that tells PowerShell which column(s) should be visible:
# show "DisplayName", and "DependentServices"
[string[]]$visible = 'DisplayName', 'DependentServices'
$type = 'DefaultDisplayPropertySet'
[System.Management.Automation.PSMemberInfo[]]$info =
[System.Management.Automation.PSPropertySet]::new($type,$visible)


Get-Service | 
    Where-Object CanStop | 
    # add the secret object to each object that you pipe into Out-GridView:
    Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $info -PassThru |
    Out-GridView -Title 'Service to stop?' -OutputMode Single | 
    Stop-Service -WhatIf

Unfortunately, when you do this, you may encounter red error messages. Some PowerShell objects (like services, for example) already use the clever trick we tried to add so you cannot overwrite the PSStandardMembers property. To work around this, simply clone the objects by running them through Select-Object *:

# create object that tells PowerShell which column(s) should be visible:
# show "DisplayName", and "DependentServices"
[string[]]$visible = 'DisplayName', 'DependentServices'
$type = 'DefaultDisplayPropertySet'
[System.Management.Automation.PSMemberInfo[]]$info =
[System.Management.Automation.PSPropertySet]::new($type,$visible)


Get-Service | 
    Where-Object CanStop | 
    # clone the objects so they now belong to you:
    Select-Object -Property * |
    # add the secret object to each object that you pipe into Out-GridView:
    Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $info -PassThru |
    Out-GridView -Title 'Service to stop?' -OutputMode Single | 
    Stop-Service -WhatIf

Now everything works like a charm, and Out-GridView only shows the properties you chose. Still, Stop-Process continues to understand the output and stops the service you chose (remove -WhatIf to really stop a service, and make sure you have Administrator privileges to do so).

While running objects through Select-Object does change their object type, most cmdlets still continue to process these objects because they still contain all properties. Here is a last example that illustrates: even though Out-GridView only shows the properties you choose, the objects still contain all properties including those that were hidden in the grid view window:

# create object that tells PowerShell which column(s) should be visible:
# show "Name", "Description" and "MainWindowTitle"
[string[]]$visible = 'Name', 'Description', 'MainWindowTitle'
$type = 'DefaultDisplayPropertySet'
[System.Management.Automation.PSMemberInfo[]]$info =
[System.Management.Automation.PSPropertySet]::new($type,$visible)


Get-Process | 
    Where-Object MainWindowTitle | 
    Sort-Object -Property Name |
    # clone the objects so they now belong to you:
    Select-Object -Property * |
    # add the secret object to each object that you pipe into Out-GridView:
    Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $info -PassThru |
    Out-GridView -Title 'Select a process' -OutputMode Single |
    # still all properties available:
    Select-Object -Property *


Twitter This Tip! ReTweet this Tip!