PowerShell反向CSV数据

在networking上,我发现这个function从PowerShell中的Excel工作表中导入数据。 我已经尝试了一下,提高了一下,结果很好。 然而,我需要采取的最后一道关键是扭转数据。 由于并非Excel工作表中的所有数据都是垂直alignment的,有时也是水平alignment的。 我想这个例子可能会变得更清楚。

'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:

 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的解决scheme:

 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 

我find了解决我的问题。 将此添加到参数部分[Switch]$Reverse并用下面的代码replace代码的结尾:

 # 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 

我认为将是一个更清洁的解决scheme将采取UsedRange,复制它,与移调粘贴特殊,然后像往常一样处理。 这是你的整个function修改,做到这一点:

 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 

好吧,原来我错过了$UsedRange = $workbookObject.ActiveSheet.UsedRange ,但现在已经修复了。 我还在While循环中确保CSV被写入,然后再试图parsing$Result =行。 我也在PasteSpecial行之后添加了一个out-null,来屏蔽真实的响应。 这工作,我只是有最初的问题,因为我testing的XLSX有空行,转置时,导致空头,这不是很酷。 另外,我在G1,H1和I1中有相同的值,所以它试图为三列使用相同的头文件,并且默默地失败,所以它只会响应一无所有。 没有错误,没有。 沮丧排除故障。 无论如何,我testing了这一点,它为我工作。