在网络上,我发现此功能可以从PowerShell中的Excel工作表导入数据。我试图加强它,但效果很好。但是,我需要采取的最后一个障碍是扭转数据。由于并非Excel工作表中的所有数据都是垂直对齐的,有时也是水平对齐的。我想通过一个例子可能会更清楚。
' Test.xlsx'
的示例Below you will find all the parameters:
Header 1 | Text 1 | Text 11
Header 2 | Text 2 | Text 22
Header 3 | Text 3 | Text 33
目前错误的结果:
Header 1 Text 1 Text 11
-------- ------ -------
Header 2 Text 2 Text 22
Header 3 Text 3 Text 33
期望的结果:
Header 1 Header 2 Header 3
-------- -------- --------
Text 1 Text 2 Text 3
Text 11 Text 22 Text 33
正如您所看到的,在某种程度上,我需要能够反转数据列和标题以使其全部正确。如果能够以Switch
的方式将其添加到函数中,那将是很好的。因此,当它不需要时,它仍然能够以旧方式导入行和列。
功能:
Function Import-Excel {
Param (
[parameter(Mandatory=$true,Position=0)]
[ValidateScript({Test-Path $_ -PathType Leaf })]
[String]$FileName,
[parameter(Mandatory=$true,Position=1)]
[String]$WorksheetName,
[parameter(Mandatory=$false,Position=2)]
[Int]$SkipLines
)
$csvFile = Join-Path $env:temp ("{0}.csv" -f (Get-Item -path $FileName).BaseName)
if (Test-Path -path $csvFile) { Remove-Item -path $csvFile }
Function FindSheet([Object]$workbook, [string]$name)
{
$sheetNumber = 0
for ($i=1; $i -le $workbook.Sheets.Count; $i++) {
if ($name -eq $workbook.Sheets.Item($i).Name) { $sheetNumber = $i; break }
}
return $sheetNumber
}
Function SetActiveSheet([Object]$workbook, [string]$name)
{
if (!$name) { return }
$sheetNumber = FindSheet $workbook $name
if ($sheetNumber -gt 0) { $workbook.Worksheets.Item($sheetNumber).Activate() }
return ($sheetNumber -gt 0)
}
# convert Excel file to CSV file
$xlCSVType = 6 # SEE: http://msdn.microsoft.com/en-us/library/bb241279.aspx
$excelObject = New-Object -ComObject Excel.Application
$excelObject.Visible = $false
$workbookObject = $excelObject.Workbooks.Open($FileName)
# check if worksheet exists
foreach ($sheet in $workbookObject.Worksheets) {
if ($Sheet.Name -eq $WorksheetName) {
$SheetAvailable = $true
}
}
if (-not $SheetAvailable) {
$workbookObject.Close()
$excelObject.Quit()
throw "Import-Excel: Worksheet '$WorksheetName' not found in workbook '$FileName'"
}
SetActiveSheet $workbookObject $WorksheetName | Out-Null
$workbookObject.SaveAs($csvFile,$xlCSVType)
$workbookObject.Saved = $true
$workbookObject.Close()
# cleanup
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbookObject) | Out-Null
$excelObject.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excelObject) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# import and return the data
$Result = Get-Content -Path $csvFile | Select-Object -Skip $SkipLines | Where {$_ -notmatch "^[,]+$"} | ConvertFrom-Csv
Write-Output $Result
}
Import-Excel C:\Test.xlsx -WorksheetName 'Parameters' -SkipLines 1
一如既往,感谢您的帮助。
解决方案感谢TheMadTechnician:
Function Import-Excel {
[CmdletBinding(SupportsShouldProcess=$True)]
Param (
[parameter(Mandatory=$true,Position=0)]
[ValidateScript({Test-Path $_ -PathType Leaf })]
[String]$FileName,
[parameter(Mandatory=$true,Position=1)]
[String]$WorksheetName,
[parameter(Mandatory=$false,Position=2)]
[Int]$SkipLines=0,
[Switch]$Reverse
)
BEGIN {
$csvFile = Join-Path $env:temp ("{0}.csv" -f (Get-Item -path $FileName).BaseName)
if (Test-Path -path $csvFile) { Remove-Item -path $csvFile }
}
PROCESS {
# Convert Excel file to CSV file
$xlCSVType = 6 # SEE: http://msdn.microsoft.com/en-us/library/bb241279.aspx
$excelObject = New-Object -ComObject Excel.Application
$excelObject.Visible = $false
$workbookObject = $excelObject.Workbooks.Open($FileName)
# Check if worksheet exists
$ws1 = $workbookObject.worksheets | where {$_.name -eq $WorksheetName}
if ($ws1 -ne $Null) {
$ws1.Activate()
}
else {
$workbookObject.Close($false)
$excelObject.Quit()
throw "Import-Excel: Worksheet '$WorksheetName' not found in workbook '$FileName'"
}
If($Reverse){
$usedRange = $workbookObject.ActiveSheet.UsedRange
$ws = $workbookObject.ActiveSheet
# Remove first lines
for ($i = 1; $i -le $SkipLines; $i++) {
[void]$ws.Cells.Item(1, 1).EntireRow.Delete()
}
# Remove empty lines
$lastCell = $usedRange.SpecialCells(11)
$row = $lastCell.row
for ($i = 1; $i -le $row; $i++) {
If ($ws.Cells.Item($i, 1).Value() -eq $Null) {
$Range = $ws.Cells.Item($i, 1).EntireRow
$Range.Delete() | Out-Null
}
}
$usedRange.Copy() | Out-Null
$newWorkbookObject = $excelObject.Workbooks.Add()
$newWorkbookObject.ActiveSheet.Range("A1").PasteSpecial(12,-4142,$false,$true)| Out-Null
$newWorkbookObject.SaveAs($csvFile,$xlCSVType)
$newWorkbookObject.Saved = $true
$newWorkbookObject.Close()
$workbookObject.Close($false)
# Pause to let the CSV be written
While(!(Test-Path $csvFile)){Start-Sleep -Milliseconds 50}
# Import and return the data
$Result = Get-Content -Path $csvFile | ConvertFrom-Csv
Write-Output $Result
}
Else{
$WorkbookObject.SaveAs($csvFile,$xlCSVType)
$WorkbookObject.Saved = $true
$workbookObject.Close()
# Pause to let the CSV be written
While(!(Test-Path $csvFile)){Start-Sleep -Milliseconds 50}
# Import and return the data
$Result = Get-Content -Path $csvFile | Select-Object -Skip $SkipLines | Where {$_ -notmatch "^[,]+$"} | ConvertFrom-Csv
Write-Output $Result
}
# Cleanup
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbookObject) | Out-Null
If($Reverse){[System.Runtime.Interopservices.Marshal]::ReleaseComObject($newWorkbookObject) | Out-Null}
$excelObject.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excelObject) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
}
Import-Excel C:\Test.xlsx -WorksheetName 'Parameters' -Reverse -SkipLines 1
答案 0 :(得分:1)
我找到了解决问题的方法。将其添加到参数部分[Switch]$Reverse
并用以下代码替换代码的结尾:
# import and return the data
$Result = Get-Content -Path $csvFile | Select-Object -Skip $SkipLines | Where {$_ -notmatch "^[,]+$"}
if ($Reverse) {
$Result | ForEach-Object {$Header += "$($_.Split(',')[0]),"; $Content += "$($_.Split(',')[1]),"}
$Result = "$Header`n$Content"
}
$Obj = $Result | ConvertFrom-Csv
Write-Output $Obj
答案 1 :(得分:1)
我认为更清洁的解决方案是使用UsedRange,复制它,使用Transpose特殊粘贴,然后像往常一样处理它。以下是您修改的整个功能:
Function Import-Excel {
Param (
[parameter(Mandatory=$true,Position=0)]
[ValidateScript({Test-Path $_ -PathType Leaf })]
[String]$FileName,
[parameter(Mandatory=$true,Position=1)]
[String]$WorksheetName,
[parameter(Mandatory=$false,Position=2)]
[Int]$SkipLines=0,
[Switch]$Reverse
)
$csvFile = Join-Path $env:temp ("{0}.csv" -f (Get-Item -path $FileName).BaseName)
if (Test-Path -path $csvFile) { Remove-Item -path $csvFile }
Function FindSheet([Object]$workbook, [string]$name)
{
$sheetNumber = 0
for ($i=1; $i -le $workbook.Sheets.Count; $i++) {
if ($name -eq $workbook.Sheets.Item($i).Name) { $sheetNumber = $i; break }
}
return $sheetNumber
}
Function SetActiveSheet([Object]$workbook, [string]$name)
{
if (!$name) { return }
$sheetNumber = FindSheet $workbook $name
if ($sheetNumber -gt 0) { $workbook.Worksheets.Item($sheetNumber).Activate() }
return ($sheetNumber -gt 0)
}
# convert Excel file to CSV file
$xlCSVType = 6 # SEE: http://msdn.microsoft.com/en-us/library/bb241279.aspx
$excelObject = New-Object -ComObject Excel.Application
$excelObject.Visible = $false
$workbookObject = $excelObject.Workbooks.Open($FileName)
# check if worksheet exists
foreach ($sheet in $workbookObject.Worksheets) {
if ($Sheet.Name -eq $WorksheetName) {
$SheetAvailable = $true
}
}
if (-not $SheetAvailable) {
$workbookObject.Close()
$excelObject.Quit()
throw "Import-Excel: Worksheet '$WorksheetName' not found in workbook '$FileName'"
}
SetActiveSheet $workbookObject $WorksheetName | Out-Null
If($Reverse){
$usedRange = $workbookObject.ActiveSheet.UsedRange
$usedRange.Copy() | Out-Null
$newWorkbookObject = $excelObject.Workbooks.Add()
$newWorkbookObject.ActiveSheet.Range("A1").PasteSpecial(12,-4142,$false,$true)|out-null
$newWorkbookObject.SaveAs($csvFile,$xlCSVType)
$newWorkbookObject.Saved = $true
$newWorkbookObject.Close()
}Else{
$WorkbookObject.SaveAs($csvFile,$xlCSVType)
$WorkbookObject.Saved = $true
$workbookObject.Close()
}
# cleanup
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbookObject) | Out-Null
If($Reverse){[System.Runtime.Interopservices.Marshal]::ReleaseComObject($newWorkbookObject) | Out-Null}
$excelObject.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excelObject) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# Pause to let the CSV be written...
While(!Test-Path $csvFile){Start-Sleep -Milliseconds 50}
# import and return the data
$Result = Get-Content -Path $csvFile | Select-Object -Skip $SkipLines | Where {$_ -notmatch "^[,]+$"} | ConvertFrom-Csv
Write-Output $Result
}
Import-Excel C:\Test.xlsx -WorksheetName 'Parameters' -SkipLines 1
好的,原来我错过了.ActiveSheet
中的$UsedRange = $workbookObject.ActiveSheet.UsedRange
,但现在已经修好了。我还设置了一个While循环,以确保在我们尝试为$Result =
行解析CSV之前写入CSV。我还在PasteSpecial
行之后添加了一个out-null,以禁止屏幕上的True响应。这是有效的,我刚刚遇到了初始问题,因为我正在测试的XLSX上有空白行,当转置时会导致空标题,这并不酷。另外,我在G1,H1和I1中具有相同的值,因此它尝试对三列使用相同的标题,并且默认失败,因此它只会响应任何内容。没有错误,没有。令人沮丧地排除故障。无论如何,我测试了这个,它对我有用。