Export-CSV -Append
Here’s the solution for those who need to append rows to existing CSV files (andcannot do that): I have just used PowerShell 2.0 code snippets to create a proxy cmdlet – function which wraps standard Export-CSV
cmdlet but adds handling of the-Append
parameter.
So you can do something like:
Get-Process | Export-Csv -Path 'c:\Temp\processes.csv' -Append -Delimiter ';'
As you can see, other parameters – such as Delimiter – still function as well. If the file does not exist – the cmdlet will essentially ignore -Append and create the file as normal. If you specify -Append and the file is present, the function will turn the objects into CSV strings, remove the first row with the property names and append to the existing file.
For your convenience, I have posted the source code to PoshCode. Here’s it is as well for those interested:
#Requires -Version 2.0 <# This Export-CSV behaves exactly like native Export-CSV However it has one optional switch -Append Which lets you append new data to existing CSV file: e.g. Get-Process | Select ProcessName, CPU | Export-CSV processes.csv -Append For details, see http://dmitrysotnikov.wordpress.com/2010/01/19/export-csv-append/ (c) Dmitry Sotnikov #> function Export-CSV { [CmdletBinding(DefaultParameterSetName='Delimiter', SupportsShouldProcess=$true, ConfirmImpact='Medium')] param( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [System.Management.Automation.PSObject] ${InputObject}, [Parameter(Mandatory=$true, Position=0)] [Alias('PSPath')] [System.String] ${Path}, #region -Append (added by Dmitry Sotnikov) [Switch] ${Append}, #endregion [Switch] ${Force}, [Switch] ${NoClobber}, [ValidateSet('Unicode','UTF7','UTF8','ASCII','UTF32', 'BigEndianUnicode','Default','OEM')] [System.String] ${Encoding}, [Parameter(ParameterSetName='Delimiter', Position=1)] [ValidateNotNull()] [System.Char] ${Delimiter}, [Parameter(ParameterSetName='UseCulture')] [Switch] ${UseCulture}, [Alias('NTI')] [Switch] ${NoTypeInformation}) begin { # This variable will tell us whether we actually need to append # to existing file $AppendMode = $false try { $outBuffer = $null if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) { $PSBoundParameters['OutBuffer'] = 1 } $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Export-Csv', [System.Management.Automation.CommandTypes]::Cmdlet) #String variable to become the target command line $scriptCmdPipeline = '' # Add new parameter handling #region Dmitry: Process and remove the Append parameter if it is present if ($Append) { $PSBoundParameters.Remove('Append') | Out-Null if ($Path) { if (Test-Path $Path) { # Need to construct new command line $AppendMode = $true if ($Encoding.Length -eq 0) { # ASCII is default encoding for Export-CSV $Encoding = 'ASCII' } # For Append we use ConvertTo-CSV instead of Export $scriptCmdPipeline += 'ConvertTo-Csv -NoTypeInformation ' # Inherit other CSV convertion parameters if ( $UseCulture ) { $scriptCmdPipeline += ' -UseCulture ' } if ( $Delimiter ) { $scriptCmdPipeline += " -Delimiter '$Delimiter' " } # Skip the first line (the one with the property names) $scriptCmdPipeline += ' | Foreach-Object {$start=$true}' $scriptCmdPipeline += '{if ($start) {$start=$false} else {$_}} ' # Add file output $scriptCmdPipeline += " | Out-File -FilePath '$Path'" $scriptCmdPipeline += " -Encoding '$Encoding' -Append " if ($Force) { $scriptCmdPipeline += ' -Force' } if ($NoClobber) { $scriptCmdPipeline += ' -NoClobber' } } } } $scriptCmd = {& $wrappedCmd @PSBoundParameters } if ( $AppendMode ) { # redefine command line $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock( $scriptCmdPipeline ) } else { # execute Export-CSV as we got it because # either -Append is missing or file does not exist $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock( [string]$scriptCmd ) } # standard pipeline initialization $steppablePipeline = $scriptCmd.GetSteppablePipeline( $myInvocation.CommandOrigin) $steppablePipeline.Begin($PSCmdlet) } catch { throw } } process { try { $steppablePipeline.Process($_) } catch { throw } } end { try { $steppablePipeline.End() } catch { throw } } <# .ForwardHelpTargetName Export-Csv .ForwardHelpCategory Cmdlet #> }
Hope this helps!
20 Responses to “Export-CSV -Append”
Tagged: powershell, windows server

Reader beware, you can have some problems if you append a different kind of object (or number of columns) than what is already in the file.
Yes, good point Jason! In my code I am NOT checking whether the property names are the same. Or that delimiter is the same. Or that encoding is the same. And so on. It is up to user to make sure that appended data matches the original one.
How exactly would one go about formatting data to match the original? For example:
Data in csv is from SMO dataFile object containing server, dbname, size, usedSpace, freespace.
I want to append a TOTAL row for each instance after all of the databases have been appended. I have tried building my own object/string and appending it to the csv, but I can’t seem to get it right. Any help would be much appreciated.
Here is what I have tried:
$totalString = “@{Server=$servername; dbname=$total; Size=$totalsize; UsedSpace=$totalUsed; FreeSpace=$totalFree}”;
(above, with and without, @, {}, and quotes)
$totalString = @”
Server : $servername
dbname : $total
Size : $totalsize
UsedSpace : $totalUsed
FreeSpace : $totalFree
“@
$totalstring | export-csv c:\test.csv -append;
Thanks,
TIm
Thanks, I am an admin, who is not a good coder. This is a great help for me and makes my life a lot easier.
Many Thanks
I’m glad that I could help, John!
Hi,
Im quite new with powershell and this post regarding Export-CSV with append is very helpful to complete my automated script reports.
I just don’t know how to use it. What do you mean with “Add this function to your profile to make Export-CSV cmdlet handle -Append parameter” in the poshcode.org?
I just need to make it work and use the -Append of Export-CSV and time is killing me due to my deadline.
Thanks in advance.
Alvin,
PowerShell profile is a script which gets loaded each time you start PowerShell. Here’s how you locate and edit it in PowerGUI Script Editor:http://dmitrysotnikov.wordpress.com/2008/01/25/dude-wheres-my-powershell-profile/
Dmitry
Thanks. It worked! I was able to do it and had the -Append on Export-CSV.
One more question though, What if I want to make sure that this profile will be used all the time? My script will run as a scheduled job and placed on different server.
Is there a way that I can call the same profile just to make sure that the code will be executed, or is it possible that I can include that at the top of the code as one of the validation process?
Thanks for the help.![:D]()
Alvin.
ei,![:)]()
I got it working. Thanks. Appreciate the help.
Alvin
Glad that I could help!![:)]()
I am having trouble using this script. When I use the command, I get an error saying “The varialbe ‘$UseCulture’ cannot be retrieved because it has not been set”. The error references line 96 and char 21. Please help.
Thanks,
Jamie
Jamie,
Looks like you have strict mode on, and this somehow does not like the parameter declarations of the function.
One easy workaround that I see is to simply add Set-StrictMode -Off to the biginning of the script… If this is unacceptable, you’ll need to figure out how to make the PowerShell parser consider the parameters ok to use in the script – let me know if you manage to do that.
Dmitry
Dimitry
I’m wondering if you can help me understand this piece of code in from your script (modified slightly to illustrate an example):
get-psdrive | foreach-object {$start=$true} {if ($start) {$start=$false} else {$_}}
I understand the point–skip first row and it works perfectly. I’ve seen scriptblocks before, but this one looks odd.
The first block is the foreach-object block and the second block, well I don’t understand how the pipeline is able to continue to pipe objects.
My previous question was answered via Twitter by Bartek
“Looks like -begin and -process blocks. So the {$start = $true} is run only once, before obj arrive”
Sure enough get-help foreach-object mentions these params, but the documentation incorrectly states they are named params.
Am I missing something? While I greatly appreciate this code, and I could not code myself out of a brown paper bag, isn’t this an excessive amount of code to simply append a file? I mean that with all due respect and I am more than likely missing something, but this seems counter to the simplicity of the intended nature of PowerShell. I am one person that is finding PowerShell to be powerful, but not all that simple. I rarely have time to code and read and it seems like a significant amount of time is required to learn PowerShell to this degree. Maybe I’m dumb? I dunno… :p
Code works great. I tried writing my own using 2 additional temp files, which was far shorter, but kept ending up with blank lines I couldn’t seem to remove. I used this code and the file came out perfect! Thanks!