Powershell: Select-Object -ExcludeProperty dependency on -Property is unintuitive.

Created on 23 Sep 2016  路  6Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

Get-Service -Name Spooler | Select-Object -ExcludeProperty Status

Expected behavior

Return a Selected.System.ServiceProcess.ServiceController object with all standard properties of System.ServiceProcess.ServiceController except Status.

Actual behavior

Returns System.ServiceProcess.ServiceController object with all properties including status.

To get the desired behavior you must use the -Property parameter in conjunction with the -ExcludeProperty parameter, this is explained in the help documentation for select-object as:

"This parameter is effective only when the command also includes the Property parameter."

I don't understand the case where you would want to declare to explicitly include a property, then exclude it again such as:

Get-Service -Name Spooler | Select-Object -Property Status -ExcludeProperty Status

Therefore the convention is to always pass "-Property *" when using the -ExcludeProperty parameter. I would suggest defaulting to -Property * when using the -ExcludeProperty cmdlet, if that would be considered a breaking change, I would suggest throwing an error if -ExcludeProperty is used without -Property indicating that you are missing a mandatory parameter since ExcludeProperty is dependent on -Property.

Environment data

> $PSVersionTable
Name                           Value                                                                                                                                                                                                                                                                                                                      
----                           -----                                                                                                                                                                                                                                                                                                                      
PSVersion                      5.0.10586.63                                                                                                                                                                                                                                                                                                               
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                                                                                                                                                                                                                                    
BuildVersion                   10.0.10586.63                                                                                                                                                                                                                                                                                                              
CLRVersion                     4.0.30319.42000                                                                                                                                                                                                                                                                                                            
WSManStackVersion              3.0                                                                                                                                                                                                                                                                                                                        
PSRemotingProtocolVersion      2.3                                                                                                                                                                                                                                                                                                                        
SerializationVersion           1.1.0.1   
Area-Cmdlets Up-for-Grabs

Most helpful comment

As an additional note, while testing I found that if I used the -Property * pattern on an object with only one property it returned a property named *.

ex:
[pscustomobject]@{Status = 'Running'} | Select-Object -Property * -ExcludeProperty Status

Returns:
*
-

Whereas
[pscustomobject]@{Status = 'Running'} | Select-Object -Property Status -ExcludeProperty Status

returns null as expected.

All 6 comments

As an additional note, while testing I found that if I used the -Property * pattern on an object with only one property it returned a property named *.

ex:
[pscustomobject]@{Status = 'Running'} | Select-Object -Property * -ExcludeProperty Status

Returns:
*
-

Whereas
[pscustomobject]@{Status = 'Running'} | Select-Object -Property Status -ExcludeProperty Status

returns null as expected.

I just hit this bug today, I exclude properties based on other criteria and I have a scenario where it should exclude all properties but instead of returning nothing I get a property named * with no value.

As a work around I am using | where {$_.psobject.Properties.name -ne "*"} to filter this bad result out.

Ex:
[pscustomobject]@{Thing="thing1"} | Select-Object -Property * -ExcludeProperty thing

Returns:
*
-

Adding the filter:
[pscustomobject]@{Thing="thing1"} | Select-Object -Property * -ExcludeProperty thing | where {$_.psobject.Properties.name -ne "*"}

Returns:

Adding in another property that should pass through with the filter still in place:
[pscustomobject]@{Thing="thing1";thing2="thing2"} | Select-Object -Property * -ExcludeProperty thing | where {$_.psobject.Properties.name -ne "*"}

Returns:
thing2
------
thing2

Thanks for the comments Chris, Our solution also involved the PSObject. We ended up just doing something like:

$object = [pscustomobject]@{Thing="thing1"}
$object.PSObject.Properties.Remove('Thing')
$object

Which returns null and can be looped on to remove multiple properties.

I would suggest throwing an error if -ExcludeProperty is used without -Property indicating that you are missing a mandatory parameter since ExcludeProperty is dependent on -Property

This is a breaking change.

the convention is to always pass "-Property *" when using the -ExcludeProperty parameter

As a solution to this issue, it is very simple and non-breaking change.

For second issue I opened #2420

Was this page helpful?
0 / 5 - 0 ratings