Excel (PowerShell)

From vwiki
Jump to navigation Jump to search

{{#widget:Widget:GoogleAdSenseSkyscraper}} Using PowerShell you can easily export a table of data to a CSV file...

Export-CSV FileToWriteTo.CSV -InputObject $DataTable -NoTypeInformation

... but you can't create an Excel file, directly. Which is a limitation if you want to create an automated (spreadsheet) report for anybody that's incapable of digesting information that's not nicely presented. To do so, requires direct automation of Excel...

Limitations

Microsoft Office applications are not built for background automation. It can be achieved, but there are some gotchas. Most notably when it comes to scheduling automation to run outside of an interactive user session. Which means you spend time crafting a wonderful script that creates a beautifully formatted spreadsheet; but which fails to complete properly when run as a scheduled task when you're not logged into the machine its running from. It also means that every once in a blue moon, it can still fail for no obvious reason.

Unable to Save Workaround

At the final stage of automation, when your script comes to attempt to save the spreadsheet it fails with an unimaginative Exception calling “SaveAs” with “1″ argument(s): “SaveAs method of Workbook class failed” error. Creating either of the following files resolves the error...

  • C:\Windows\System32\config\systemprofile\Desktop
    • For 32 bit only or 64 bit only systems
  • C:\Windows\SysWOW64\config\systemprofile\Desktop
    • For mixed systems where 32 bit Excel is running on 64 bit OS

This error is probably specific to Excel 2007 and later (Excel 2010 is affected), running on Windows 7, 2008 and later

Create From CSV

Whilst its not necessary to create a CSV as an intermediate step, it can be beneficial to do so because...

  • Its easier to create/maintain your script as you can see whats going on with the data
  • When the Excel automation fails you can attempt to repeat or complete manually, rather than re-running the data collection/creation part.

Basic example, converting an existing CSV file into a XLSX file.

$INfile = "VMs.csv"                                     # Has three columns, labelled VC, Name, Datastore
$OUTfile = "VMs.xlsx"

$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $False                                 # Set to $true if you want actually see the script interact with Excel

$ExcelBook = $Excel.Workbooks.Add()

$Excel.Rows.Item(1).Font.Bold = $true                   # Bold heading text
$Excel.Rows.Item(1).VerticalAlignment = -4108           # Centre (vertically) heading
$Excel.Rows.Item(1).HorizontalAlignment = -4108         # Centre (horizontally) heading

$Excel.Cells.Item(1,1) = "VC"
$Excel.Cells.Item(1,2) = "VM Name"
$Excel.Cells.Item(1,3) = "Datastore"

$CSVfile = Import-Csv -Path $INfile

$row = 2

foreach($line in $CSVfile) {
    $Excel.Cells.Item($row,1) = $line.VC
    $Excel.Cells.Item($row,2) = $line.Name
    $Excel.Cells.Item($row,3) = $line.Datastore
    $row += 1
    Write-Host "." -NoNewLine
}

$ExcelBook.SaveAs($OUTfile)
$Excel.Quit()
Remove-Variable -Name Excel
[gc]::Collect()
[gc]::WaitForPendingFinalizers()

Formatting

Example Description
$Excel.Rows.Item(1).Font.Bold = $True Make row 1 bold
$Excel.Rows.Item(1).WrapText = $True Make row 1 wrap text (may affect row height)
$Excel.Rows.Item(1).VerticalAlignment = -4108 Centre (vertically) text on 1st row
$Excel.Rows.Item(1).HorizontalAlignment = -4108 Centre (horizontally) text on 1st row
$Excel.Columns.Item(1).columnWidth = 12 Make column 1 have a width of 12
$Excel.Cells.EntireColumn.AutoFit() Auto-fit all columns
$Excel.Cells.EntireColumn.AutoFilter() Auto-filter all columns
$Excel.Columns.Borders.LineStyle = 1 Give all cells a simple border

To freeze panes...

[void]$Excel.Cells.Item(2,3).Select()           # Select the appropriate cell to freeze around
$Excel.ActiveWindow.FreezePanes = $True         # Freeze

Conditional Formatting

See http://robertrobelo.wordpress.com/2010/10/07/excels-conditional-formatting-and-powershell/#comments