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.

[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.

Share this:

  • Print (Opens in new window) Print

Like this:

Like Loading…

Related

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

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