Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

powershell piped input to export-csv different from -inputobject

Tags:

powershell

csv

In Powershell (3.0), I get different results when piping an object to Export-CSV than I do if I use the -IncludeObject parameter with the same object.

Example:

$a = Get-Process | select -first 5
$a | Export-CSV -Path '.\one.csv'
Export-CSV -InputObject $a -Path '.\two.csv'

Why are the contents of one.csv and two.csv different?

(And in case it's just me ...)

one.csv =

    #TYPE System.Diagnostics.Process
"__NounName","Name","Handles","VM","WS","PM","NPM","Path","Company","CPU","FileVersion","ProductVersion","Description","Product","BasePriority","ExitCode","HasExited","ExitTime","Handle","HandleCount","Id","MachineName","MainWindowHandle","MainWindowTitle","MainModule","MaxWorkingSet","MinWorkingSet","Modules","NonpagedSystemMemorySize","NonpagedSystemMemorySize64","PagedMemorySize","PagedMemorySize64","PagedSystemMemorySize","PagedSystemMemorySize64","PeakPagedMemorySize","PeakPagedMemorySize64","PeakWorkingSet","PeakWorkingSet64","PeakVirtualMemorySize","PeakVirtualMemorySize64","PriorityBoostEnabled","PriorityClass","PrivateMemorySize","PrivateMemorySize64","PrivilegedProcessorTime","ProcessName","ProcessorAffinity","Responding","SessionId","StartInfo","StartTime","SynchronizingObject","Threads","TotalProcessorTime","UserProcessorTime","VirtualMemorySize","VirtualMemorySize64","EnableRaisingEvents","StandardInput","StandardOutput","StandardError","WorkingSet","WorkingSet64","Site","Container"
"Process","AATray","390","156721152","29769728","10678272","27600","C:\Program Files\IBM\ISAM ESSO\AA\AATray.exe","IBM Corporation","42.4166719","8.2.1.1143","8.2.1.1143","AccessAgent Tray Icon: Component of ISAM ESSO AccessAgent","ISAM ESSO AccessAgent","8",,"False",,"4844","390","7784",".","0","","System.Diagnostics.ProcessModule (AATray.exe)","1413120","204800","System.Diagnostics.ProcessModuleCollection","27600","27600","10678272","10678272","257536","257536","63672320","63672320","29806592","29806592","194101248","194101248","True","Normal","10678272","10678272","00:00:32.8070103","AATray","15","True","1","System.Diagnostics.ProcessStartInfo","8/2/2016 7:20:30 AM",,"System.Diagnostics.ProcessThreadCollection","00:00:42.4166719","00:00:09.6096616","156721152","156721152","False",,,,"29769728","29769728",,
"Process","ac.activclient.gui.scagent","547","155099136","22593536","8478720","33184","C:\Program Files\ActivIdentity\ActivClient\ac.activclient.gui.scagent.exe","HID Global Identity Assurance","2.2932147","7,0,5,17","7,0","ActivClient Agent","${release.product.name}","8",,"False",,"3648","547","7872",".","0","","System.Diagnostics.ProcessModule (ac.activclient.gui.scagent.exe)","1413120","204800","System.Diagnostics.ProcessModuleCollection","33184","33184","8478720","8478720","274408","274408","62431232","62431232","22659072","22659072","168542208","168542208","True","Normal","8478720","8478720","00:00:01.8876121","ac.activclient.gui.scagent","15","True","1","System.Diagnostics.ProcessStartInfo","8/2/2016 7:20:30 AM",,"System.Diagnostics.ProcessThreadCollection","00:00:02.2932147","00:00:00.4056026","155099136","155099136","False",,,,"22593536","22593536",,
"Process","accagt","166","508174336","17592320","25407488","26116",,,,,,,,"8",,,,,"166","2480",".","0","",,,,,"26116","26116","25407488","25407488","159440","159440","25657344","25657344","17694720","17694720","509747200","509747200",,,"25407488","25407488",,"accagt",,"True","0","System.Diagnostics.ProcessStartInfo",,,"System.Diagnostics.ProcessThreadCollection",,,"508174336","508174336","False",,,,"17592320","17592320",,
"Process","acevents","506","140414976","22474752","8048640","30856","C:\Program Files\ActivIdentity\ActivClient\acevents.exe","HID Global Identity Assurance","42.6350733","5,0,4,4","5,0","ActivIdentity Event Service","ActivClient Services","8",,"False",,"3872","506","8256",".","0","","System.Diagnostics.ProcessModule (acevents.exe)","1413120","204800","System.Diagnostics.ProcessModuleCollection","30856","30856","8048640","8048640","249632","249632","61378560","61378560","22528000","22528000","157003776","157003776","True","Normal","8048640","8048640","00:00:24.6013577","acevents","15","True","1","System.Diagnostics.ProcessStartInfo","8/2/2016 7:20:34 AM",,"System.Diagnostics.ProcessThreadCollection","00:00:42.6350733","00:00:18.0337156","140414976","140414976","False",,,,"22474752","22474752",,
"Process","acnamagent","395","98971648","14561280","6586368","28296",,,,,,,,"8",,,,,"395","2012",".","0","",,,,,"28296","28296","6586368","6586368","125784","125784","6647808","6647808","14594048","14594048","101597184","101597184",,,"6586368","6586368",,"acnamagent",,"True","0","System.Diagnostics.ProcessStartInfo",,,"System.Diagnostics.ProcessThreadCollection",,,"98971648","98971648","False",,,,"14561280","14561280",,

two.csv =

#TYPE System.Object[]
"Count","Length","LongLength","Rank","SyncRoot","IsReadOnly","IsFixedSize","IsSynchronized"
"5","5","5","1","System.Object[]","False","True","False"

For context, I'm trying to splat my parameters to Export-CSV, but I run into this when I pass -InputObject, and I can't pipe the input and then splat the rest of the parameters.

Thanks.

like image 892
Ed Chandler Avatar asked Aug 04 '16 16:08

Ed Chandler


1 Answers

This is the expected behavior.

When you pipe in through the pipeline, arrays, collections, enumerable stuff, etc. gets processed item by item. This is usually what you want.

When you use -InputObject, it accepts the array as a single object.

The best way to see this is to use Get-Member:

$a = Get-Process | select -first 5
$a | Get-Member
Get-Member -InputObject $a

In the first invocation, you'll see the data type and members of each element. In the second invocation you'll see the type and members of the collection object.

Depending on the cmdlet, you may not notice difference at all because it's handling both cases (see the pipeline function at the end of my answer).

But in the case of Export-Csv, or ConvertTo-Json, or other serialization type cmdlets, you want this difference; otherwise it's very difficult to serialize the array explicitly when you want to.

Another way to demonstrate it:

$sb = {
    $_
    Write-Verbose $_.Count -Verbose
}

$a | ForEach-Object -Process $sb
ForEach-Object -Process $sb -InputObject $a

When writing your own pipeline functions, a common way to work around the different ways of receiving the object is to use the Process {} block along with foreach:

function Test-Pipeline {
[CmdletBinding()]
param(
    [Parameter(ValueFromPipeline)]
    $MyVal
)

    Process {
        Write-Verbose $MyVal.Count -Verbose
        foreach($v in $MyVal) {
            $v
        }
    }
}

$a | Test-Pipeline  
# Process block gets called once for each element

Test-Pipeline -MyVal $a  
# Process block gets called once total, with the variable being an array

This works well because foreach doesn't fail if you give it a single non-array object, it just executes once.

like image 171
briantist Avatar answered Nov 15 '22 05:11

briantist