Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Select Object Properties with Values

Posted on August 16, 2011August 12, 2011

Here's another concept I know I've written about in the past but that needed an update. A common technique I use when exploring and discovering objects is to pipe the object to Select-Object specifying all properties, get-service spooler | select *. There's nothing wrong with this approach but depending on the object I might get a lot of empty values. This is especially true with WMI objects or items from Active Directory like a user account. The other issue I have is that when using this technique with a WMI object, I also get the system properties like __PATH, which I'd often like to ignore. The solution I came up is a function called Select-PropertyValue. Pipe objects to the function and it will write a custom object to the pipeline only with properties that have a value.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

[cc lang="PowerShell"]
Function Select-PropertyValue {
[cmdletbinding()]

Param(
[Parameter(Position=0,ValueFromPipeline=$True)]
[object]$InputObject,
[Switch]$NoSystem,
[Switch]$Inquire = $False
)

Begin {
Write-Verbose "Starting $($myinvocation.mycommand)"

#define a variable we will be using to keep StrictMode happy.
$properties=@()
} #begin

Process {

<# set debug preference to continue when using -Debug unless user has also used -Inquire. Otherwise, PowerShell will prompt for each command. Due to scoping issues I found the best solution was to set the debug preference for each object in the pipeline #>

if (($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("debug")) -AND (-NOT $Inquire)) {
$DebugPreference="Continue"
}

Write-Debug "In process"
Write-Debug "Checking for `$properties"
<# because this only takes pipelined objects, we only need to get the properties from Get-Member once. When the second object is processed, this IF block will get skipped. The assumption that all pipelined objects are of the same type. #>

if (-Not $properties) {
Write-Verbose "Creating property list"
Write-Debug "Creating property list for pipelined object"

#get properties for the pipelined object sorted by property name
$properties=$_ | Get-Member -membertype Properties | sort Name
$typename=($_ |Get-Member)[0].TypeName
Write-Debug "Typename =$typename"

#filter out WMI System properties if -NoSystem
if ($NoSystem) {
Write-Verbose "Filtering out WMI System properties"
Write-Debug "Filtering out WMI System properties."
$properties=$properties | where {$_.name -notlike "__*"}
}

Write-Verbose "Found $($properties.count) properties"
Write-Debug "Found $($properties.count) properties"
}

#create an empty custom object
Write-Debug "Creating empty object"
$obj=New-Object PSObject

#enumerate the list of properties
Write-Verbose "Checking properties for values"
foreach ($property in $properties) {
Write-Debug "Checking $($property.name)"
#if object has a value for the current property
if ($_.($property.name)) {
Write-Debug "found value for: $($_.($property.name))"

#assign properties to the custom object
Write-Debug "Adding property and value to custom object"
$obj | Add-Member -MemberType Noteproperty -name $property.Name -value ($_.($property.name))

} #end If
} #end ForEach

#Add the typename to the object
Write-Debug "Adding typename to custom object"
$obj | Add-Member -MemberType Noteproperty -Name "Type" -Value $typename

#write the custom object to the pipeline
Write-Debug "Writing custom object to the pipeline"
Write $obj
} #end process

End {
Write-Verbose "Ending $($myinvocation.mycommand)"
}

} #end function
[/cc]

The function is intended to be used in a pipelined expression and assumes that all the objects are of the same type. The essence of the function is to run each object through Get-Member and keep a list of property names.

[cc lang="PowerShell"]
if (-Not $properties) {
Write-Verbose "Creating property list"
Write-Debug "Creating property list for pipelined object"
$properties=$_ | Get-Member -membertype Properties | sort Name
[/cc]

Because this happens in the process script block, which runs once for every piped in object, this line only runs if $properties doesn't already exist. If the user includes the -NoSystem parameter, then any property that starts with __ is removed.

[cc lang="PowerShell"]
if ($NoSystem) {
Write-Verbose "Filtering out WMI System properties"
Write-Debug "Filtering out WMI System properties."
$properties=$properties | where {$_.name -notlike "__*"}
}
[/cc]

Armed with the array of property names, the pipelined object is checked for each property name.

[cc lang="PowerShell"]
foreach ($property in $properties) {
Write-Debug "Checking $($property.name)"
#if object has a value for the current property
if ($_.($property.name)) {
Write-Debug "found value for: $($_.($property.name))"
[/cc]

If a value is found

[cc lang="PowerShell"]
if ($_.($property.name))
[/cc]

Then the property and value are added to the blank custom object which is created for each piped object.

[cc lang="PowerShell"]
$obj | Add-Member -MemberType Noteproperty -name $property.Name -value ($_.($property.name))
[/cc]

I include the object type name and write the custom object to the pipeline.

[cc lang="PowerShell"]
#Add the typename to the object
Write-Debug "Adding typename to custom object"
$obj | Add-Member -MemberType Noteproperty -Name "Type" -Value $typename

#write the custom object to the pipeline
Write-Debug "Writing custom object to the pipeline"
Write $obj
[/cc]

Here's the end result.

[cc lang="DOS"]
BiosCharacteristics : {4, 7, 8, 9...}
BIOSVersion : {TOSQCI - 6040000, Ver 1.00PARTTBL}
Caption : Ver 1.00PARTTBL
Description : Ver 1.00PARTTBL
Manufacturer : TOSHIBA
Name : Ver 1.00PARTTBL
PrimaryBIOS : True
ReleaseDate : 20101210000000.000000+000
SerialNumber : Z9131790W
SMBIOSBIOSVersion : V2.90
SMBIOSMajorVersion : 2
SMBIOSMinorVersion : 6
SMBIOSPresent : True
SoftwareElementID : Ver 1.00PARTTBL
SoftwareElementState : 3
Status : OK
Version : TOSQCI - 6040000
Type : System.Management.ManagementObject#root\cimv2\Win32_BIOS
[/cc]

You probably also noticed the Write-Verbose and Write-Debug lines in the script. Continuing the discussion I started in my post on Write-Verbose vs Write-Debug, I'm including the suggestion on controlling the debug preference. By default if you the function with -debug you'll get all the debug messages. But if you also use -Inquire, then you'll get prompted for each command which is the normal process when using -Debug. I wanted to see how this would work in one of my own scripts.

As always, I hope you'll let me know how this works out for you. Download Select-PropertyValue. The full script includes comment-based help as well as an optional alias. Uncomment the last line of the script if you want to use it or define your own.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d