qbanet359's helpful answer uses direct property access (.LoadPercentage
) on the result object, which is the simplest and most efficient solution in this case.
In PowerShell v3+ this even works with extracting property values from a collection (array, list) of objects, via a feature called member-access enumeration.
E.g., ((Get-Date), (Get-Date).AddYears(-1)).Year
returns 2019
and 2018
when run in 2019, which are the .Year
property values from each [datetime]
instance in the array.
In cases where you do want to use Select-Object
(or its built-in alias, select
), such as when processing a large input collection item by item, so as to take advantage of potentially memory-friendly streaming processing:
To use Select-Object
to extract a single property value, you must use -ExpandProperty
:
Get-WmiObject win32_processor | Select-Object -ExpandProperty LoadPercentage
As zett42 notes, using ForEach-Object
with simplified syntax is another option, which, when using the built-in %
alias makes for a concise solution that is handy for interactive use:
# Short for: ForEach-Object -MemberName LoadPercentage
# which in turn is equivalent to: ForEach-Object { $_.LoadPercentage }
Get-WmiObject win32_processor | % LoadPercentage
- As an aside re performance (probably won't matter in most cases): Surprisingly,
ForEach-Object -MemberName LoadPercentage
is slower than
ForEach-Object { $_.LoadPercentage }
, up to at least PowerShell 7.3.4 (the current version as of this writing); see GitHub issue #7700.
Background information:
Select-Object
by default creates custom objects ([pscustomobject]
instances[1]
) that have the properties you specify via the -Property
parameter (optionally implicitly, as the 1st positional argument).
This applies even when specifying a single property[2], so that select LoadPercentage
(short for: Select-Object -Property LoadPercentage
) creates something like the following object:
$obj = [pscustomobject] @{ LoadPercentage = 4 } # $obj.LoadPercentage yields 4
Because you use Add-Content
to write to your log file, it is the .ToString()
string representation of that custom object that is written, as you would get if you used the object in an expandable string (try "$([pscustomobject] @{ LoadPercentage = 4 })"
).
By contrast, parameter -ExpandProperty
, which can be applied to a single property only, does not create a custom object and instead returns the value of that property from the input object.
- Note: If the value of that property happens to be an array (collection), its elements are output individually; that is, you'll get multiple outputs per input object.
[1] Strictly speaking, they're [System.Management.Automation.PSCustomObject]
instances, whereas type accelerator [pscustomobject]
, confusingly, refers to type [System.Management.Automation.PSObject]
, for historical reasons; see this GitHub issue.
[2] There's a hotly debated request on GitHub to change Select-Object
's default behavior with only a single property; while the discussion is interesting, the current behavior is unlikely to change.