Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between using and not using pipe in Export-Csv in Powershell

Tags:

powershell

csv

This is probably more of a 'how does PowerShell handle variables and piping' rather than a specific programmatical question, but since it seems like strange behaviour (to me) I thought I'd post it here.

I just had some difficulties exporting a variable to a CSV using PowerShell and found this Stack question that helped me a lot. However, when fiddling around with the output I got two different results depending on how I called the Export-CSV function.

I have a custom PS object that looks roughly like this:

Account      Partner     ProjectName     ProjectPhase
1            A           Test            Start
2            B           Test2           Start
3            A           Test4           End
4            C           Test3           Middle
....

When I use the following line it correctly outputs the CSV file:

$csvBody | Export-Csv -Path "$targetPath\$fileName" -Encoding Unicode -NoTypeInformation

However, when I use the following line it doesn't:

Export-Csv -InputObject $csvBody -Path "$targetPath\$fileName" -Encoding Unicode -NoTypeInformation

In this case, the output looks like this: Count,"Length","LongLength","Rank","SyncRoot","IsReadOnly","IsFixedSize","IsSynchronized" 263,"263","263","1","System.Object[]","False","True","False"

I understand from this other Stack post that the output becomes the property of the $csvBody, which is an array. My question is why does this happen when I'm not piping the object to Export-CSV, but it doesn't happen when I am using the pipe?

like image 309
Tanaka Saito Avatar asked Feb 05 '23 13:02

Tanaka Saito


2 Answers

I think this is because Export-CSV has been written with the intention that it should (and would) generally handle input via the pipeline.

I think the behavior you are seeing occurs because the -InputObject parameter does not accept array input. You can see that from the help page:

   Export-Csv [[-Path] <String>] [[-Delimiter] <Char>] [-Append] [-Confirm] [-Encoding <String> {Unicode | UTF7 |
   UTF8 | ASCII | UTF32 | BigEndianUnicode | Default | OEM}] [-Force] -InputObject <PSObject> [-LiteralPath <String>]
   [-NoClobber] [-NoTypeInformation] [-WhatIf] [<CommonParameters>]

It is <psobject> rather than <psobject[]> and as such it expects a single <psobject> as it's input. It seemingly doesn't unroll that object when it's provided via the parameter line, instead it gives you a CSV that contains the default properties of that object itself (length etc.).

When you send the object via the pipeline, it uses the cmdlet PROCESS functionality of accepting pipeline input to unroll the object and handle each item in the collection individually.

Someone can probably explain this better than I have above, or perhaps can explain why Export-CSV doesn't work the way you expect (other than --as I assume-- by design).

like image 154
Mark Wragg Avatar answered Apr 29 '23 21:04

Mark Wragg


Here everything works as design and not badly written :

In the second way, the inputobject is a #TYPE System.Object[] as you can see if you keep TypeInformation.

When you call Export-Csv using the pipe, each object of the collection is sent to the process part of the Cmdlet.


Take a collection of integers :

$a = 1..4

then try :

$a | Get-Member

It gives : System.Int32

Then try :

Get-Member -InputObject $a

It gives : System.Object[]

So in your case the object exported is the array wich can be useful too.

like image 41
JPBlanc Avatar answered Apr 29 '23 21:04

JPBlanc