简体   繁体   English

如何使用 Powershell 将 CSV 导出到 Excel

[英]How to export a CSV to Excel using Powershell

I'm trying to export a complete CSV to Excel by using Powershell.我正在尝试使用 Powershell 将完整的 CSV 导出到 Excel。 I stuck at a point where static column names are used.我停留在使用静态列名的地方。 But this doesn't work if my CSV has generic unknown header names.但是,如果我的 CSV 具有通用的未知标题名称,则这不起作用。

Steps to reproduce重现步骤

Open your PowerShell ISE and copy & paste the following standalone code.打开您的 PowerShell ISE 并复制并粘贴以下独立代码。 Run it with F5F5运行它
"C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell_ise.exe" “C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell_ise.exe”

Get-Process | Export-Csv -Path $env:temp\process.csv -NoTypeInformation

$processes = Import-Csv -Path $env:temp\process.csv 
$Excel = New-Object -ComObject excel.application 
$workbook = $Excel.workbooks.add() 

$i = 1 
foreach($process in $processes) 
{ 
 $excel.cells.item($i,1) = $process.name
 $excel.cells.item($i,2) = $process.vm
 $i++ 
} 
Remove-Item $env:temp\process.csv
$Excel.visible = $true

What it does它的作用

  1. The script will export a list of all active processes as a CSV to your temp folder.该脚本会将所有活动进程的列表作为 CSV 导出到您的临时文件夹。 This file is only for our example.此文件仅用于我们的示例。 It could be any CSV with any data它可以是包含任何数据的任何 CSV
  2. It reads in the newly created CSV and saves it under the $processes variable它读入新创建的 CSV 并将其保存在$processes变量下
  3. It creates a new and empty Excel workbook where we can write data它会创建一个新的空 Excel 工作簿,我们可以在其中写入数据
  4. It iterates through all rows (?) and writes all values from the name and vm column to Excel它遍历所有行 (?) 并将namevm列中的所有值写入 Excel

My questions我的问题

  • What if I don't know the column headers?如果我不知道列标题怎么办? (In our example name and vm ). (在我们的示例中namevm )。 How do I address values where I don't know their header names?如何处理我不知道标头名称的值?
  • How do I count how many columns a CSV has?我如何计算 CSV 有多少列? (after reading it with Import-Csv ) (使用Import-Csv阅读后)

I just want to write an entire CSV to Excel with Powershell我只想用 Powershell 将整个 CSV 写入 Excel

Ups, I entirely forgot this question. Ups,我完全忘记了这个问题。 In the meantime I got a solution.与此同时,我得到了一个解决方案。
This Powershell script converts a CSV to XLSX in the background此 Powershell 脚本在后台将 CSV 转换为 XLSX

Gimmicks are噱头是

  • Preserves all CSV values as plain text like =B1+B2 or 0000001 .将所有 CSV 值保留为纯文本,如=B1+B20000001
    You don't see #Name or anything like that.你看不到#Name或类似的东西。 No autoformating is done.没有自动格式化。
  • Automatically chooses the right delimiter (comma or semicolon) according to your regional setting根据您的区域设置自动选择正确的分隔符(逗号或分号)
  • Autofit columns自动调整列

PowerShell Code PowerShell 代码

### Set input and output path
$inputCSV = "C:\somefolder\input.csv"
$outputXLSX = "C:\somefolder\output.xlsx"

### Create a new Excel Workbook with one empty sheet
$excel = New-Object -ComObject excel.application 
$workbook = $excel.Workbooks.Add(1)
$worksheet = $workbook.worksheets.Item(1)

### Build the QueryTables.Add command
### QueryTables does the same as when clicking "Data » From Text" in Excel
$TxtConnector = ("TEXT;" + $inputCSV)
$Connector = $worksheet.QueryTables.add($TxtConnector,$worksheet.Range("A1"))
$query = $worksheet.QueryTables.item($Connector.name)

### Set the delimiter (, or ;) according to your regional settings
$query.TextFileOtherDelimiter = $Excel.Application.International(5)

### Set the format to delimited and text for every column
### A trick to create an array of 2s is used with the preceding comma
$query.TextFileParseType  = 1
$query.TextFileColumnDataTypes = ,2 * $worksheet.Cells.Columns.Count
$query.AdjustColumnWidth = 1

### Execute & delete the import query
$query.Refresh()
$query.Delete()

### Save & close the Workbook as XLSX. Change the output extension for Excel 2003
$Workbook.SaveAs($outputXLSX,51)
$excel.Quit()

I am using excelcnv.exe to convert csv into xlsx and that seemed to work properly.我正在使用 excelcnv.exe 将 csv 转换为 xlsx,这似乎工作正常。 You will have to change the directory to where your excelcnv is.您必须将目录更改为 excelcnv 所在的位置。 If 32 bit, it goes to Program Files (x86)如果是 32 位,则转到 Program Files (x86)

Start-Process -FilePath 'C:\Program Files\Microsoft Office\root\Office16\excelcnv.exe' -ArgumentList "-nme -oice ""$xlsFilePath"" ""$xlsToxlsxPath"""

Why would you bother?你为什么要打扰? Load your CSV into Excel like this:将您的 CSV 加载到 Excel 中,如下所示:

$csv = Join-Path $env:TEMP "process.csv"
$xls = Join-Path $env:TEMP "process.xlsx"

$xl = New-Object -COM "Excel.Application"
$xl.Visible = $true

$wb = $xl.Workbooks.OpenText($csv)

$wb.SaveAs($xls, 51)

You just need to make sure that the CSV export uses the delimiter defined in your regional settings.您只需要确保 CSV 导出使用区域设置中定义的分隔符。 Override with -Delimiter if need be.如果需要,用-Delimiter覆盖。


Edit: A more general solution that should preserve the values from the CSV as plain text.编辑:一个更通用的解决方案,应该将 CSV 中的值保留为纯文本。 Code for iterating over the CSV columns taken from here .用于迭代从此处获取的 CSV 列的代码。

$csv = Join-Path $env:TEMP "input.csv"
$xls = Join-Path $env:TEMP "output.xlsx"

$xl = New-Object -COM "Excel.Application"
$xl.Visible = $true

$wb = $xl.Workbooks.Add()
$ws = $wb.Sheets.Item(1)

$ws.Cells.NumberFormat = "@"

$i = 1
Import-Csv $csv | ForEach-Object {
  $j = 1
  foreach ($prop in $_.PSObject.Properties) {
    if ($i -eq 1) {
      $ws.Cells.Item($i, $j++).Value = $prop.Name
    } else {
      $ws.Cells.Item($i, $j++).Value = $prop.Value
    }
  }
  $i++
}

$wb.SaveAs($xls, 51)
$wb.Close()

$xl.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)

Obviously this second approach won't perform too well, because it's processing each cell individually.显然,第二种方法不会表现得很好,因为它单独处理每个单元格。

This topic really helped me, so I'd like to share my improvements.这个话题对我很有帮助,所以我想分享我的改进。 All credits go to the nixda , this is based on his answer.所有学分都归于 nixda ,这是基于他的回答。

For those who need to convert multiple csv's in a folder, just modify the directory.对于那些需要在一个文件夹中转换多个 csv 的人,只需修改目录即可。 Outputfilenames will be identical to input, just with another extension.输出文件名将与输入相同,只是具有另一个扩展名。

Take care of the cleanup in the end, if you like to keep the original csv's you might not want to remove these .最后请注意清理,如果您想保留原始 csv,您可能不想删除这些 .csv 文件

Can be easily modifed to save the xlsx in another directory.可以轻松修改以将 xlsx 保存在另一个目录中。

$workingdir = "C:\data\*.csv"
$csv = dir -path $workingdir
foreach($inputCSV in $csv){
$outputXLSX = $inputCSV.DirectoryName + "\" + $inputCSV.Basename + ".xlsx"
### Create a new Excel Workbook with one empty sheet
$excel = New-Object -ComObject excel.application 
$excel.DisplayAlerts = $False
$workbook = $excel.Workbooks.Add(1)
$worksheet = $workbook.worksheets.Item(1)

### Build the QueryTables.Add command
### QueryTables does the same as when clicking "Data » From Text" in Excel
$TxtConnector = ("TEXT;" + $inputCSV)
$Connector = $worksheet.QueryTables.add($TxtConnector,$worksheet.Range("A1"))
$query = $worksheet.QueryTables.item($Connector.name)

### Set the delimiter (, or ;) according to your regional settings
### $Excel.Application.International(3) = ,
### $Excel.Application.International(5) = ;
$query.TextFileOtherDelimiter = $Excel.Application.International(5)

### Set the format to delimited and text for every column
### A trick to create an array of 2s is used with the preceding comma
$query.TextFileParseType  = 1
$query.TextFileColumnDataTypes = ,2 * $worksheet.Cells.Columns.Count
$query.AdjustColumnWidth = 1

### Execute & delete the import query
$query.Refresh()
$query.Delete()

### Save & close the Workbook as XLSX. Change the output extension for Excel 2003
$Workbook.SaveAs($outputXLSX,51)
$excel.Quit()
}
## To exclude an item, use the '-exclude' parameter (wildcards if needed)
remove-item -path $workingdir -exclude *Crab4dq.csv

If you want to convert CSV to Excel without Excel being installed, you can use the great .NET library EPPlus (under LGPL license) to create and modify Excel Sheets and also convert CSV to Excel really fast!如果您想在不安装 Excel 的情况下将 CSV 转换为 Excel,您可以使用强大的 .NET 库EPPlus (在 LGPL 许可下)来创建和修改 Excel 表格,并将 CSV 转换为 Excel 非常快!

Preparation准备

  1. Download the latest stable EPPlus version下载最新的稳定版EPPlus
  2. Extract EPPlus to your preferred location (eg to $HOME\\Documents\\WindowsPowerShell\\Modules\\EPPlus )将 EPPlus 提取到您的首选位置(例如,到$HOME\\Documents\\WindowsPowerShell\\Modules\\EPPlus
  3. Right Click EPPlus.dll, select Properties and at the bottom of the General Tab click "Unblock" to allow loading of this dll.右键单击 EPPlus.dll,选择“属性”,然后在“常规”选项卡底部单击“取消阻止”以允许加载此 dll。 If you don't have the rights to do this, try [Reflection.Assembly]::UnsafeLoadFrom($DLLPath) | Out-Null如果您无权这样做,请尝试[Reflection.Assembly]::UnsafeLoadFrom($DLLPath) | Out-Null [Reflection.Assembly]::UnsafeLoadFrom($DLLPath) | Out-Null

Detailed Powershell Commands to import CSV to Excel将 CSV 导入 Excel 的详细 Powershell 命令

# Create temporary CSV and Excel file names
$FileNameCSV = "$HOME\Downloads\test.csv"
$FileNameExcel = "$HOME\Downloads\test.xlsx"

# Create CSV File (with first line containing type information and empty last line)
Get-Process | Export-Csv -Delimiter ';' -Encoding UTF8 -Path $FileNameCSV

# Load EPPlus
$DLLPath = "$HOME\Documents\WindowsPowerShell\Modules\EPPlus\EPPlus.dll"
[Reflection.Assembly]::LoadFile($DLLPath) | Out-Null

# Set CSV Format
$Format = New-object -TypeName OfficeOpenXml.ExcelTextFormat
$Format.Delimiter = ";"
# use Text Qualifier if your CSV entries are quoted, e.g. "Cell1","Cell2"
$Format.TextQualifier = '"'
$Format.Encoding = [System.Text.Encoding]::UTF8
$Format.SkipLinesBeginning = '1'
$Format.SkipLinesEnd = '1'

# Set Preferred Table Style
$TableStyle = [OfficeOpenXml.Table.TableStyles]::Medium1

# Create Excel File
$ExcelPackage = New-Object OfficeOpenXml.ExcelPackage 
$Worksheet = $ExcelPackage.Workbook.Worksheets.Add("FromCSV")

# Load CSV File with first row as heads using a table style
$null=$Worksheet.Cells.LoadFromText((Get-Item $FileNameCSV),$Format,$TableStyle,$true) 

# Load CSV File without table style
#$null=$Worksheet.Cells.LoadFromText($file,$format) 

# Fit Column Size to Size of Content
$Worksheet.Cells[$Worksheet.Dimension.Address].AutoFitColumns()

# Save Excel File
$ExcelPackage.SaveAs($FileNameExcel) 

Write-Host "CSV File $FileNameCSV converted to Excel file $FileNameExcel"

This is a slight variation that worked better for me.这是一个对我来说效果更好的轻微变化

$csv = Join-Path $env:TEMP "input.csv"
$xls = Join-Path $env:TEMP "output.xlsx"

$xl = new-object -comobject excel.application
$xl.visible = $false
$Workbook = $xl.workbooks.open($CSV)
$Worksheets = $Workbooks.worksheets

$Workbook.SaveAs($XLS,1)
$Workbook.Saved = $True

$xl.Quit()

I had some problem getting the other examples to work.我在让其他示例工作时遇到了一些问题。

EPPlus and other libraries produces OpenDocument Xml format, which is not the same as you get when you save from Excel as xlsx. EPPlus 和其他库生成 OpenDocument Xml 格式,这与您从 Excel 保存为 xlsx 时获得的格式不同。

macks example with open CSV and just re-saving didn't work, I never managed to get the ',' delimiter to be used correctly. macks 示例与开放的 CSV 和只是重新保存没有工作,我从来没有设法让 ',' 分隔符被正确使用。

Ansgar Wiechers example has some slight error which I found the answer for in the commencts. Ansgar Wiechers 的例子有一些小错误,我在评论中找到了答案。

Anyway, this is a complete working example.无论如何,这是一个完整的工作示例。 Save this in a File CsvToExcel.ps1将此保存在文件 CsvToExcel.ps1 中

param (
[Parameter(Mandatory=$true)][string]$inputfile,
[Parameter(Mandatory=$true)][string]$outputfile
)

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false

$wb = $excel.Workbooks.Add()
$ws = $wb.Sheets.Item(1)

$ws.Cells.NumberFormat = "@"

write-output "Opening $inputfile"

$i = 1
Import-Csv $inputfile | Foreach-Object { 
    $j = 1
    foreach ($prop in $_.PSObject.Properties)
    {
        if ($i -eq 1) {
            $ws.Cells.Item($i, $j) = $prop.Name
        } else {
            $ws.Cells.Item($i, $j) = $prop.Value
        }
        $j++
    }
    $i++
}

$wb.SaveAs($outputfile,51)
$wb.Close()
$excel.Quit()
write-output "Success"

Execute with:执行:

.\CsvToExcel.ps1 -inputfile "C:\Temp\X\data.csv" -outputfile "C:\Temp\X\data.xlsx"

I found this while passing and looking for answers on how to compile a set of csvs into a single excel doc with the worksheets (tabs) named after the csv files.我在通过并寻找有关如何将一组 csvs 编译成单个 excel 文档的答案时发现了这一点,其中工作表(选项卡)以 csv 文件命名。 It is a nice function.这是一个不错的功能。 Sadly, I cannot run them on my network :( so i do not know how well it works.遗憾的是,我无法在我的网络上运行它们 :( 所以我不知道它的效果如何。

Function Release-Ref ($ref)
{
    ([System.Runtime.InteropServices.Marshal]::ReleaseComObject(
    [System.__ComObject]$ref) -gt 0)
    [System.GC]::Collect()
    [System.GC]::WaitForPendingFinalizers()
    }
    Function ConvertCSV-ToExcel
    {
    <#
    .SYNOPSIS
    Converts     one or more CSV files into an excel file.
    
    .DESCRIPTION
    Converts one or more CSV files into an excel file. Each CSV file is imported into its own worksheet with the name of the
    file being the name of the worksheet.
        
    .PARAMETER inputfile
    Name of the CSV file being converted
    
    .PARAMETER output
    Name of the converted excel file
    
    .EXAMPLE
    Get-ChildItem *.csv | ConvertCSV-ToExcel -output ‘report.xlsx’
    
    .EXAMPLE
    ConvertCSV-ToExcel -inputfile ‘file.csv’ -output ‘report.xlsx’
    
    .EXAMPLE
    ConvertCSV-ToExcel -inputfile @(“test1.csv”,”test2.csv”) -output ‘report.xlsx’
    
    .NOTES
    Author:     Boe Prox
    Date Created: 01SEPT210
    Last Modified:
    
    #>
    
    #Requires -version 2.0
    [CmdletBinding(
    SupportsShouldProcess = $True,
    ConfirmImpact = ‘low’,
    DefaultParameterSetName = ‘file’
    )]
    Param (
    [Parameter(
    ValueFromPipeline=$True,
    Position=0,
    Mandatory=$True,
    HelpMessage=”Name of CSV/s to import”)]
    [ValidateNotNullOrEmpty()]
    [array]$inputfile,
    [Parameter(
    ValueFromPipeline=$False,
    Position=1,
    Mandatory=$True,
    HelpMessage=”Name of excel file output”)]
    [ValidateNotNullOrEmpty()]
    [string]$output
    )
    
    Begin {
    #Configure regular expression to match full path of each file
    [regex]$regex = “^\w\:\\”
    
    #Find the number of CSVs being imported
    $count = ($inputfile.count -1)
    
    #Create Excel Com Object
    $excel = new-object -com excel.application
    
    #Disable alerts
    $excel.DisplayAlerts = $False
    
    #Show Excel application
    $excel.V    isible = $False
    
    #Add workbook
    $workbook = $excel.workbooks.Add()
    
    #Remove other worksheets
    $workbook.worksheets.Item(2).delete()
    #After the first worksheet is removed,the next one takes its place
    $workbook.worksheets.Item(2).delete()
    
    #Define initial worksheet number
    $i = 1
    }
    
    Process {
    ForEach ($input in $inputfile) {
    #If more than one file, create another worksheet for each file
    If ($i -gt 1) {
    $workbook.worksheets.Add() | Out-Null
    }
    #Use the first worksheet in the workbook (also the newest created worksheet is always 1)
    $worksheet = $workbook.worksheets.Item(1)
    #Add name of CSV as worksheet name
    $worksheet.name = “$((GCI $input).basename)”
    
    #Open the CSV file in Excel, must be converted into complete path if no already done
    If ($regex.ismatch($input)) {
    $tempcsv = $excel.Workbooks.Open($input)
    }
    ElseIf ($regex.ismatch(“$($input.fullname)”)) {
    $tempcsv = $excel.Workbooks.Open(“$($input.fullname)”)
    }
    Else {
    $tempcsv = $excel.Workbooks.Open(“$($pwd)\$input”)
    }
    $tempsheet = $tempcsv.Worksheets.Item(1)
    #Copy contents of the CSV file
    $tempSheet.UsedRange.Copy() | Out-Null
    #Paste contents of CSV into existing workbook
    $worksheet.Paste()
    
    #Close temp workbook
    $tempcsv.close()
    
    #Select all used cells
    $range = $worksheet.UsedRange
    
    #Autofit the columns
    $range.EntireColumn.Autofit() | out-null
    $i++
    }
    }
    
    End {
    #Save spreadsheet
    $workbook.saveas(“$pwd\$output”)
    
    Write-Host -Fore Green “File saved to $pwd\$output”
    
    #Close Excel
    $excel.quit()
    
    #Release processes for Excel
    $a = Release-Ref($range)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM