Because PowerShell is all about the objects, I often point out to beginners to use the Select-Object cmdlet to see all the properties of an object and their values.
PS C:\> get-process powershell | select *
Using Get-Member is helpful to discover property names but sometimes you need to see a value to know which property or properties you really want to work with. That’s where my Select-Object suggestion comes in. Unfortunately not every property is defined for every object so you can end up with a lot of empty properties. What I wanted was a way to only display properties for an object that have a value. Here’s my solution.
I wrote a filtering function called Select-PropertyValue.
Filter Select-PropertyValue {
Param([switch]$NoWMISystem,[switch]$debug)
if ($debug) {
$debugPreference="Continue"
}
Write-Debug "In process"
if (-Not $properties) {
Write-Debug "Creating property list"
#get properties for the pipelined object sorted by property name
$properties=$_ | Get-Member -membertype Properties | sort Name
#filter out WMI System properties if -NoWMISystem
if ($NoWMISystem) {
Write-Debug "Filtering out WMI System properties"
$properties=$properties | where {$_.name -notlike "__*"}
}
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
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 $($_.($property.name))"
#assign properties
$obj | Add-Member -MemberType Noteproperty -name $property.Name -value ($_.($property.name))
} #end If
} #end ForEach
#write the custom object to the pipeline
write $obj
} #end function
This function is designed to accept pipelined input. Normally you would write such a function with Begin, Process and End scriptblocks. However if you don’t use the Begin and End scriptblocks, you can create a filter as I’ve done. The filtering function’s code is what would be found in the Process scriptblock.
The function can also take two parameters, -debug and -NoWMISystem. The former will enable debug messages throughout the function. I inserted Write-Debug commands throughout the function so I could track what was happening. Using -debug allows me to see the output of those commands. The second parameter will suppress the system classes associated with a WMI object such as __RELPATH and __GENUS. I rarely need to see this information.
To use the function I first dot source the ps1 file as it also creates an alias for the function, spv. Now I can run command like this:
PS C:\> gwmi win32_bios | spv -noWMISystem
The WIn32_Bios object is piped to the function. The first step the function takes is to build a variable with all of the property names for the pipelined object.
if (-Not $properties) {
Write-Debug "Creating property list"
#get properties for the pipelined object sorted by property name
$properties=$_ | Get-Member -membertype Properties | sort Name
These are stored in a variable, $properties, that I only need to create once. It $properties already exists the function skips this step.
If I’ve specified -nowmisystem, then $properties is filtered further to remove the system classes.
#filter out WMI System properties if -NoWMISystem
if ($NoWMISystem) {
Write-Debug "Filtering out WMI System properties"
$properties=$properties | where {$_.name -notlike "__*"}
}
The function is going to create a new custom object and copy the properties that have values so it first creates an empty object.
#create an empty custom object
Write-Debug "Creating empty object"
$obj=New-Object PSObject
The $properties variable is enumerated one at a time. If the property of the pipelined object has a value, then the property name and value are added to the custom object.
#enumerate the list of properties
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 $($_.($property.name))"
#assign properties
$obj | Add-Member -MemberType Noteproperty -name $property.Name -value ($_.($property.name))
} #end If
} #end ForEach
After all the properties have been checked the object is written to the pipeline.
#write the custom object to the pipeline
write $obj
This is now more useful to me:
PS C:\> gwmi win32_bios | spv -n
BiosCharacteristics : {7, 8, 9, 11…}
BIOSVersion : {FUJ – 1180000}
Caption : Default System BIOS
CurrentLanguage : enUS
Description : Default System BIOS
InstallableLanguages : 2
ListOfLanguages : {enUS, jaJP}
Manufacturer : FUJITSU // Phoenix Technologies Ltd.
Name : Default System BIOS
PrimaryBIOS : True
ReleaseDate : 20080602000000.000000+000
SerialNumber : R6Y02331
SMBIOSBIOSVersion : Version 1.18
SMBIOSMajorVersion : 2
SMBIOSMinorVersion : 4
SMBIOSPresent : True
SoftwareElementID : Default System BIOS
SoftwareElementState : 3
Status : OK
Version : FUJ – 1180000
The function writes to the pipeline so I can pipe it to other cmdlets as well. This especially useful when you want to export as you’ll end up only exporting properties with values.
PS C:\> gwmi win32_service | spv -n | export-csv c:\test\servicedata.csv -notype
Download the script file with this function here.
Enjoy and if you extend functionality, I hope you’ll let me know.