1

I wrote a script that constructs a custom object and exports it to a CSV file:

$reg = Get-ItemProperty HKLM:\SOFTWARE\McAfee\DLP\Agent | Select-Object agentversion

$date = Get-ItemProperty 'C:\Program Files\McAfee' | Select-Object {$_.LastWriteTime} 

$date86 = Get-ItemProperty 'C:\Program Files (x86)\McAfee'| Select-Object {$_.LastWriteTime}

New-Object -TypeName pscustomobject -Property @{
  "Number1"=$reg
  "Number2"=$date86
  "Number3"=$date } | export-csv -Path C:\****\desktop\stuff.csv -NoTypeInformation

and the data row in the resulting CSV file is:

"@{AgentVersion=9.4.112.22}","@{$.LastWriteTime=5/6/2016 6:02:32 AM}","@{$.LastWriteTime=7/5/2016 8:34:01 PM}"

Is it possible to get rid of the unwanted @{<name>=...} wrappers?

mklement0
  • 382,024
  • 64
  • 607
  • 775
C.Kelly
  • 23
  • 1
  • 4

2 Answers2

1

The expression:

Select-Object {$_.LastWriteTime}

outputs an object with a single property with name $_.LastWriteTime. The simplest way to fix it is to use the -ExpandProperty parameter which will only output the value that you are interested in. e.g.:

$date86 = Get-ItemProperty 'C:\Program Files (x86)\McAfee'|
            Select-Object -ExpandProperty LastWriteTime 

Note that I've also removed the script block from the Select-Object command, as it wasn't necessary.

mklement0
  • 382,024
  • 64
  • 607
  • 775
zdan
  • 28,667
  • 7
  • 60
  • 71
1

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*
mklement0
  • 382,024
  • 64
  • 607
  • 775