5

我正在尝试使用 Powershell 将完整的 CSV 导出到 Excel。我停留在使用静态列名的地方。但是,如果我的 CSV 具有通用的未知标题名称,这将不起作用。

重现步骤

打开您的 PowerShell ISE 并复制并粘贴以下独立代码。使用F5
“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

它能做什么

  1. 该脚本会将所有活动进程的列表作为 CSV 导出到您的临时文件夹。该文件仅用于我们的示例。它可以是任何包含任何数据的 CSV
  2. 它读入新创建的 CSV 并将其保存在$processes变量下
  3. 它创建了一个新的空 Excel 工作簿,我们可以在其中写入数据
  4. 它遍历所有行(?)并将所有值从nameandvm列写入 Excel

我的问题

  • 如果我不知道列标题怎么办?(在我们的示例中namevm)。如何处理我不知道其标头名称的值?
  • 如何计算 CSV 有多少列?(用 阅读后Import-Csv

我只想用 Powershell 将整个 CSV 写入 Excel

4

8 回答 8

16

Ups,我完全忘记了这个问题。与此同时,我得到了解决方案。
此 Powershell 脚本在后台将 CSV 转换为 XLSX

噱头是

  • 将所有 CSV 值保留为纯文本,如=B1+B2or 0000001
    你看不到#Name或类似的东西。没有进行自动格式化。
  • 根据您的区域设置自动选择正确的分隔符(逗号或分号)
  • 自动调整列

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()
于 2014-01-16T18:01:21.217 回答
8

我正在使用 excelcnv.exe 将 csv 转换为 xlsx,这似乎工作正常。您必须将目录更改为您的 excelcnv 所在的位置。如果是 32 位,则转到 Program Files (x86)

Start-Process -FilePath 'C:\Program Files\Microsoft Office\root\Office16\excelcnv.exe' -ArgumentList "-nme -oice ""$xlsFilePath"" ""$xlsToxlsxPath"""
于 2019-05-16T00:06:10.267 回答
4

你为什么要打扰?像这样将您的 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)

您只需确保 CSV 导出使用您的区域设置中定义的分隔符。-Delimiter如果需要,覆盖。


编辑:一个更通用的解决方案,应该将 CSV 中的值保留为纯文本。用于迭代取自此处的 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)

显然,第二种方法的效果不会太好,因为它单独处理每个单元格。

于 2013-07-16T23:49:43.977 回答
3

这个话题真的帮助了我,所以我想分享我的改进。所有学分都归于 nixda,这是基于他的回答。

对于那些需要在一个文件夹中转换多个csv的人,只需修改目录即可。输出文件名将与输入相同,只是具有另一个扩展名。

最后请注意清理,如果您想保留原始 csv,您可能不想删除这些.

可以轻松修改以将 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
于 2016-08-30T12:24:52.060 回答
2

如果您想在没有安装 Excel 的情况下将 CSV 转换为 Excel,您可以使用出色的 .NET 库EPPlus(在 LGPL 许可下)创建和修改 Excel 表格,并将 CSV 转换为 Excel 非常快!

准备

  1. 下载最新的稳定EPPlus版本
  2. 将 EPPlus 提取到您的首选位置(例如到$HOME\Documents\WindowsPowerShell\Modules\EPPlus
  3. 右键单击 EPPlus.dll,选择属性,然后在常规选项卡的底部单击“取消阻止”以允许加载此 dll。如果您无权执行此操作,请尝试[Reflection.Assembly]::UnsafeLoadFrom($DLLPath) | Out-Null

将 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"
于 2014-12-29T15:37:45.730 回答
1

这是一个对我来说效果更好的细微变化。

$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()
于 2014-01-16T16:04:26.823 回答
0

我在让其他示例正常工作时遇到了一些问题。

EPPlus 和其他库生成 OpenDocument Xml 格式,这与您从 Excel 中保存为 xlsx 时获得的格式不同。

打开 CSV 的 macks 示例,只是重新保存不起作用,我从未设法正确使用“,”分隔符。

Ansgar Wiechers 示例有一些轻微的错误,我在评论中找到了答案。

无论如何,这是一个完整的工作示例。将此保存在文件 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"

执行:

.\CsvToExcel.ps1 -inputfile "C:\Temp\X\data.csv" -outputfile "C:\Temp\X\data.xlsx"
于 2016-05-22T14:04:38.667 回答
0

我在传递并寻找有关如何将一组 csvs 编译成一个带有以 csv 文件命名的工作表(选项卡)的单个 excel 文档的答案时发现了这一点。这是一个不错的功能。可悲的是,我无法在我的网络上运行它们 :( 所以我不知道它的效果如何。

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)
    }
}
于 2020-10-14T13:44:48.277 回答