To complement zdan's helpful answer[1]
with alternatives:
If you just want the value of a given object's property, simply wrap the command in (...)
and use .<propertyName>
:
(Get-ItemProperty 'C:\Program Files\McAfee').LastWriteTime # returns a [datetime] instance
In PSv3+, the above also works with commands returning multiple items (arrays), in which case an array of the input items' individual property values is output - this feature is called member-access enumeration.
PSv3 introduced a shortcut syntax for %
/ ForEach-Object
(and also ?
/ Where-Object
) that can be leveraged here as well :
Get-ItemProperty 'C:\Program Files\McAfee' | % LastWriteTime # ditto
This is the equivalent of the more verbose (which also works in PSv2-):
Get-ItemProperty 'C:\Program Files\McAfee' | % { $_.LastWriteTime }
These two pipeline-based syntax forms are slower, but have two advantages:
Large input collections are better processed in pipelines one by one in order to keep memory use constant (if feasible; if you need to collect the entire output in memory, there is no advantage).
This syntax unambiguously references an individual item's property rather than a property of the collection as a whole.
- E.g.,
(Get-ChildItem -File C:\Windows).Length
returns the count of files in C:\Windows
, because Length
is interpreted as the collection's (array's) property;
by contrast, Get-ChildItem -File C:\Windows | % Length
returns an array of the individual files' .Length
(file-size) property values.
Finally, in PSv4+, you may also use the .ForEach()
collection method, which doesn't use the pipeline and is therefore faster (though slightly slower than member-access enumeration), but, like member-access enumeration, requires that the input collection be in memory in full:
(Get-ItemProperty 'C:\Program Files\McAfee').ForEach('LastWriteTime')
[1] A quick overview of Select-Object
's behavior:
Select-Object [-Property] <string[]>
returns a custom object for each input object, containing only the specified properties; even with only a single property specified, the results are custom objects with that single property, not the property values themselves.
By contrast, using -ExpandProperty <string>
returns the given, single property's value from each input object (typed as-is) instead.
A simple example: extract the Year
property value from a Get-Date
call:
# WRONG: with (implied) -Property
PS> $val = Get-Date | Select-Object Year; "$val"
@{Year=2018} # !!
# A custom object with a Year property was returned and the above is its
# string representation, the equivalent of:
# "$([pscustomobject] @{ Year = 2018 })"
# CORRECT: with -ExpandProperty
PS> $val = Get-Date | Select-Object -ExpandProperty Year; "$val"
2018 # OK: -ExpandProperty extracted just the property's *value*