diff --git a/ConvertExcelToImageFile.ps1 b/ConvertExcelToImageFile.ps1 index be1ad54..6381759 100644 --- a/ConvertExcelToImageFile.ps1 +++ b/ConvertExcelToImageFile.ps1 @@ -1,15 +1,15 @@ Function Convert-XlRangeToImage { <# - .Synopsis + .Synopsis Gets the specified part of an Excel file and exports it as an image - .Description + .Description Excel allows charts to be exported directly to a file, but can't do this with the rest of a sheet. To work round this this function * Opens a copy of Excel and loads a file * Selects a worksheet and then a range of cells in that worksheet * Copies the select to the clipboard - * Saves the clipboard contents as an image file (it will save as .JPG unless the file name ends .BMP or .PNG) - * Copies a single cell to the clipboard (to prevent the "you have put a lot in the clipboard" message appearing) - * Closes Excel + * Saves the clipboard contents as an image file (it will save as .JPG unless the file name ends .BMP or .PNG) + * Copies a single cell to the clipboard (to prevent the "you have put a lot in the clipboard" message appearing) + * Closes Excel #> Param ( #Path to the Excel file @@ -20,41 +20,41 @@ Param ( #Range of cells within the sheet, e.g "A1:Z99" [parameter(Mandatory=$true)] $range, - #A bmp, png or jpg file where the result will be saved - $destination = "$pwd\temp.png", - #If specified opens the image in the default viewer. + #A bmp, png or jpg file where the result will be saved + $destination = "$pwd\temp.png", + #If specified opens the image in the default viewer. [switch]$show ) $extension = $destination -replace '^.*\.(\w+)$' ,'$1' if ($extension -in @('JPEG','BMP','PNG')) { $Format = [system.Drawing.Imaging.ImageFormat]$extension - } #if we don't recognise the extension OR if it is JPG with an E, use JPEG format - else { $Format = [system.Drawing.Imaging.ImageFormat]::Jpeg} - Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Starting Excel" + } #if we don't recognise the extension OR if it is JPG with an E, use JPEG format + else { $Format = [system.Drawing.Imaging.ImageFormat]::Jpeg} + Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Starting Excel" $xlApp = New-Object -ComObject "Excel.Application" - Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Opening Workbook and copying data" + Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Opening Workbook and copying data" $xlWbk = $xlApp.Workbooks.Open($Path) - $xlWbk.Worksheets($workSheetname).Select() + $xlWbk.Worksheets($workSheetname).Select() $xlWbk.ActiveSheet.Range($range).Select() | Out-Null $xlApp.Selection.Copy() | Out-Null - Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Saving copied data" - # Get-Clipboard came in with PS5. Older versions can use [System.Windows.Clipboard] but it is ugly. - $image = Get-Clipboard -Format Image - $image.Save($destination, $Format) - Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Closing Excel" - $xlWbk.ActiveSheet.Range("a1").Select() | Out-Null - $xlApp.Selection.Copy() | Out-Null + Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Saving copied data" + # Get-Clipboard came in with PS5. Older versions can use [System.Windows.Clipboard] but it is ugly. + $image = Get-Clipboard -Format Image + $image.Save($destination, $Format) + Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Status "Closing Excel" + $xlWbk.ActiveSheet.Range("a1").Select() | Out-Null + $xlApp.Selection.Copy() | Out-Null $xlApp.Quit() Write-Progress -Activity "Exporting $range of $workSheetname in $Path" -Completed if ($show) {Start-Process -FilePath $destination} - else {Get-Item -Path $destination} + else {Get-Item -Path $destination} } <# -del demo*.xlsx +del demo*.xlsx $workSheetname = 'Processes' $Path = "$pwd\demo.xlsx" -$myData = Get-Process | Select-Object -Property Name,WS,CPU,Description,company,startTime +$myData = Get-Process | Select-Object -Property Name,WS,CPU,Description,company,startTime $excelPackage = $myData | Export-Excel -KillExcel -Path $Path -WorkSheetname $workSheetname -ClearSheet -AutoSize -AutoFilter -BoldTopRow -FreezeTopRow -PassThru $workSheet = $excelPackage.Workbook.Worksheets[$workSheetname] @@ -63,12 +63,12 @@ Set-Format -WorkSheet $workSheet -Range "b:b" -NumberFormat Set-Format -WorkSheet $workSheet -Range "C:C" -NumberFormat "#,##0.00" -AutoFit Set-Format -WorkSheet $workSheet -Range "F:F" -NumberFormat "dd MMMM HH:mm:ss" -AutoFit Add-ConditionalFormatting -WorkSheet $workSheet -Range "c2:c1000" -DataBarColor Blue -Add-ConditionalFormatting -WorkSheet $workSheet -Range "b2:B1000" -RuleType GreaterThan -ConditionValue '104857600' -ForeGroundColor "Red" -Bold +Add-ConditionalFormatting -WorkSheet $workSheet -Range "b2:B1000" -RuleType GreaterThan -ConditionValue '104857600' -ForeGroundColor "Red" -Bold -Export-Excel -ExcelPackage $excelPackage -WorkSheetname $workSheetname +Export-Excel -ExcelPackage $excelPackage -WorkSheetname $workSheetname -Convert-XlRangeToImage -Path $Path -workSheetname $workSheetname -range $range -destination "$pwd\temp.png" -show +Convert-XlRangeToImage -Path $Path -workSheetname $workSheetname -range $range -destination "$pwd\temp.png" -show #> -Convert-XlRangeToImage -Path $Path -workSheetname $workSheetname -range $range -destination "$pwd\temp.png" -show \ No newline at end of file +#Convert-XlRangeToImage -Path $Path -workSheetname $workSheetname -range $range -destination "$pwd\temp.png" -show \ No newline at end of file diff --git a/Examples/CustomReporting/CustomReport.ps1 b/Examples/CustomReporting/CustomReport.ps1 new file mode 100644 index 0000000..16d4671 --- /dev/null +++ b/Examples/CustomReporting/CustomReport.ps1 @@ -0,0 +1,72 @@ +Import-Module ..\..\ImportExcel.psd1 -Force + +$f = ".\dashboard.xlsx" +Remove-Item $f -ErrorAction Ignore + +$data = @" +From,To,RDollars,RPercent,MDollars,MPercent,Revenue,Margin +Atlanta,New York,3602000,.0809,955000,.09,245,65 +New York,Washington,4674000,.105,336000,.03,222,16 +Chicago,New York,4674000,.0804,1536000,.14,550,43 +New York,Philadelphia,12180000,.1427,-716000,-.07,321,-25 +New York,San Francisco,3221000,.0629,1088000,.04,436,21 +New York,Phoneix,2782000,.0723,467000,.10,674,33 +"@ | ConvertFrom-Csv + +$data | Export-Excel $f -AutoSize + +$excel = Open-ExcelPackage $f + +$sheet1 = $excel.Workbook.Worksheets["sheet1"] + +$sheet1.View.ShowGridLines = $false +$sheet1.View.ShowHeaders = $false + +Set-Format -Address $sheet1.Cells["C:C"] -NumberFormat "$#,##0" -WrapText -HorizontalAlignment Center +Set-Format -Address $sheet1.Cells["D:D"] -NumberFormat "#.#0%" -WrapText -HorizontalAlignment Center + +Set-Format -Address $sheet1.Cells["E:E"] -NumberFormat "$#,##0" -WrapText -HorizontalAlignment Center +Set-Format -Address $sheet1.Cells["F:F"] -NumberFormat "#.#0%" -WrapText -HorizontalAlignment Center + +Set-Format -Address $sheet1.Cells["G:H"] -WrapText -HorizontalAlignment Center + +## Insert Rows/Columns +$sheet1.InsertRow(1, 1) + +foreach ($col in Write-Output 2 4 6 8 10 12 14) { + $sheet1.InsertColumn($col, 1) + $sheet1.Column($col).width = .75 +} + +Set-Format -Address $sheet1.Cells["E:E"] -Width 12 +Set-Format -Address $sheet1.Cells["I:I"] -Width 12 + +$BorderBottom = "Thick" +$BorderColor = "LightBlue" + +Set-Format -Address $sheet1.Cells["A2"] -BorderBottom $BorderBottom -BorderColor $BorderColor + +Set-Format -Address $sheet1.Cells["C2"] -BorderBottom $BorderBottom -BorderColor $BorderColor +Set-Format -Address $sheet1.Cells["E2:G2"] -BorderBottom $BorderBottom -BorderColor $BorderColor +Set-Format -Address $sheet1.Cells["I2:K2"] -BorderBottom $BorderBottom -BorderColor $BorderColor +Set-Format -Address $sheet1.Cells["M2:O2"] -BorderBottom $BorderBottom -BorderColor $BorderColor + +Set-Format -Address $sheet1.Cells["A2:C8"] -FontColor GrayText + +$HorizontalAlignment = "Center" +Set-Format -Address $sheet1.Cells["F1"] -HorizontalAlignment $HorizontalAlignment -Bold -Value Revenue +Set-Format -Address $sheet1.Cells["J1"] -HorizontalAlignment $HorizontalAlignment -Bold -Value Margin +Set-Format -Address $sheet1.Cells["N1"] -HorizontalAlignment $HorizontalAlignment -Bold -Value Passenger + +Set-Format -Address $sheet1.Cells["E2"] -Value '($)' +Set-Format -Address $sheet1.Cells["G2"] -Value '%' +Set-Format -Address $sheet1.Cells["I2"] -Value '($)' +Set-Format -Address $sheet1.Cells["K2"] -Value '%' + +Set-Format -Address $sheet1.Cells["C10"] -HorizontalAlignment Right -Bold -Value "Grand Total Calculation" +Set-Format -Address $sheet1.Cells["E10"] -Formula "=Sum(E3:E8)" -Bold +Set-Format -Address $sheet1.Cells["I10"] -Formula "=Sum(I3:I8)" -Bold +Set-Format -Address $sheet1.Cells["M10"] -Formula "=Sum(M3:M8)" -Bold +Set-Format -Address $sheet1.Cells["O10"] -Formula "=Sum(O3:O8)" -Bold + +Close-ExcelPackage $excel -Show \ No newline at end of file diff --git a/Examples/PivotTableFilters/testPivotFilter.ps1 b/Examples/PivotTableFilters/testPivotFilter.ps1 new file mode 100644 index 0000000..b8ff7e3 --- /dev/null +++ b/Examples/PivotTableFilters/testPivotFilter.ps1 @@ -0,0 +1,22 @@ +Import-Module ..\..\ImportExcel.psd1 -Force + +$xlFile=".\testPivot.xlsx" +Remove-Item $xlFile -ErrorAction Ignore + + +$data =@" +Region,Area,Product,Units,Cost +North,A1,Apple,100,.5 +South,A2,Pear,120,1.5 +East,A3,Grape,140,2.5 +West,A4,Banana,160,3.5 +North,A1,Pear,120,1.5 +North,A1,Grape,140,2.5 +"@ | ConvertFrom-Csv + +$data | + Export-Excel $xlFile -Show ` + -AutoSize -AutoFilter ` + -IncludePivotTable ` + -PivotRows Product ` + -PivotData @{"Units"="sum"} -PivotFilter Region, Area diff --git a/Examples/SetColumnBackgroundColor/SetColumnBackgroundColor.ps1 b/Examples/SetColumnBackgroundColor/SetColumnBackgroundColor.ps1 new file mode 100644 index 0000000..67d3738 --- /dev/null +++ b/Examples/SetColumnBackgroundColor/SetColumnBackgroundColor.ps1 @@ -0,0 +1,9 @@ + +$p = ps | select Company, Handles | Export-Excel c:\temp\testBackgroundColor.xlsx -ClearSheet -KillExcel -PassThru + +$ws = $p.Workbook.WorkSheets[1] +$totalRows = $ws.Dimension.Rows + +Set-Format -Address $ws.Cells["B2:B$($totalRows)"] -BackgroundColor LightBlue + +Export-Excel -ExcelPackage $p -show \ No newline at end of file diff --git a/Examples/TryMultiplePivotTables.ps1 b/Examples/TryMultiplePivotTables.ps1 index 7b0382b..f53338f 100644 --- a/Examples/TryMultiplePivotTables.ps1 +++ b/Examples/TryMultiplePivotTables.ps1 @@ -1,6 +1,6 @@ # To ship, is to choose -ipmo .\ImportExcel.psd1 -Force +#ipmo .\ImportExcel.psd1 -Force $pt=[ordered]@{} diff --git a/Examples/XlRangeToImage/XlRangeToImage.ps1 b/Examples/XlRangeToImage/XlRangeToImage.ps1 new file mode 100644 index 0000000..c7afbca --- /dev/null +++ b/Examples/XlRangeToImage/XlRangeToImage.ps1 @@ -0,0 +1,23 @@ +ipmo .\ImportExcel.psd1 -Force + +. .\ConvertExcelToImageFile.ps1 + +$xlFileName = "C:\Temp\testPNG.xlsx" + +rm C:\Temp\testPNG.xlsx -ErrorAction Ignore + +$range = @" +Region,Item,Cost +North,Pear,1 +South,Apple,2 +East,Grapes,3 +West,Berry,4 +North,Pear,1 +South,Apple,2 +East,Grapes,3 +West,Berry,4 +"@ | ConvertFrom-Csv | + Export-Excel $xlFileName -ReturnRange ` + -ConditionalText (New-ConditionalText Apple), (New-ConditionalText Berry -ConditionalTextColor White -BackgroundColor Purple) + +Convert-XlRangeToImage -Path $xlFileName -workSheetname sheet1 -range $range -Show diff --git a/Export-Excel.ps1 b/Export-Excel.ps1 index 0090255..5748505 100644 --- a/Export-Excel.ps1 +++ b/Export-Excel.ps1 @@ -8,7 +8,7 @@ .PARAMETER Path Path to a new or existing .XLSX file .PARAMETER ExcelPackage - An object representing an Excel Package - usually this is returned by specifying -Passthru alllowing multiple commands to work on the same Workbook without saving and reloading each time. + An object representing an Excel Package - usually this is returned by specifying -Passthru allowing multiple commands to work on the same Workbook without saving and reloading each time. .PARAMETER WorkSheetName The name of a sheet within the workbook - "Sheet1" by default .PARAMETER ClearSheet @@ -321,13 +321,13 @@ [CmdletBinding(DefaultParameterSetName = 'Default')] Param( - [Parameter(ParameterSetName="Default",Position=0)] - [Parameter(ParameterSetName="Table" ,Position=0)] + [Parameter(ParameterSetName = "Default", Position = 0)] + [Parameter(ParameterSetName = "Table" , Position = 0)] [String]$Path, - [Parameter(Mandatory=$true,ParameterSetName="PackageDefault")] - [Parameter(Mandatory=$true,ParameterSetName="PackageTable")] + [Parameter(Mandatory = $true, ParameterSetName = "PackageDefault")] + [Parameter(Mandatory = $true, ParameterSetName = "PackageTable")] [OfficeOpenXml.ExcelPackage]$ExcelPackage, - [Parameter(ValueFromPipeline=$true)] + [Parameter(ValueFromPipeline = $true)] $TargetData, [String]$Password, [String]$WorkSheetname = 'Sheet1', @@ -342,6 +342,7 @@ [String[]]$PivotRows, [String[]]$PivotColumns, $PivotData, + [String[]]$PivotFilter, [Switch]$PivotDataToColumn, [Hashtable]$PivotTableDefinition, [Switch]$IncludePivotChart, @@ -376,8 +377,8 @@ $true } })] - [Parameter(ParameterSetName = 'Table' ,Mandatory = $true)] - [Parameter(ParameterSetName = 'PackageTable' ,Mandatory = $true)] + [Parameter(ParameterSetName = 'Table' , Mandatory = $true)] + [Parameter(ParameterSetName = 'PackageTable' , Mandatory = $true)] [String]$TableName, [Parameter(ParameterSetName = 'Table')] [Parameter(ParameterSetName = 'PackageTable')] @@ -397,7 +398,10 @@ [ScriptBlock]$CellStyleSB, [Parameter(ParameterSetName = 'Now')] # [Parameter(ParameterSetName = 'TableNow')] - [Switch]$Now + [Switch]$Now, + [Switch]$ReturnRange, + [Switch]$NoTotalsInPivot, + [Switch]$ReZip ) Begin { @@ -492,7 +496,7 @@ if ($TitleBackgroundColor -AND ($TitleFillPattern -ne 'None')) { $ws.Cells[$Row, $StartColumn].Style.Fill.BackgroundColor.SetColor($TitleBackgroundColor) } - elseif ($TitleBackgroundColor) { + elseif ($TitleBackgroundColor) { Write-Warning "Title Background Color ignored. You must set the TitleFillPattern parameter to a value other than 'None'. Try 'Solid'." } } @@ -526,7 +530,7 @@ } Try { $script:Header = $null - if ($append -and $clearSheet) {throw "You can't use -Append AND -ClearSheet."} + if ($append -and $clearSheet) {throw "You can't use -Append AND -ClearSheet."} if ($KillExcel) { Stop-ExcelProcess } @@ -541,40 +545,46 @@ } if ($ExcelPackage) { - $pkg = $ExcelPackage - $Path = $pkg.File + $pkg = $ExcelPackage + $Path = $pkg.File } - Else { + Else { $Path = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path) - if (Test-Path $Path) { + $targetPath = Split-Path $Path + if (!(Test-Path $targetPath)) { + Write-Debug "Base path $($targetPath) does not exist, creating" + $null = mkdir $targetPath -ErrorAction Ignore + } + elseif (Test-Path $Path) { Write-Debug "Path '$Path' already exists" } $pkg = New-Object OfficeOpenXml.ExcelPackage $Path } - - [OfficeOpenXml.ExcelWorksheet]$ws = $pkg | Add-WorkSheet -WorkSheetname $WorkSheetname -NoClobber:$NoClobber -ClearSheet:$ClearSheet #Add worksheet doesn't take any action for -noClobber + + [OfficeOpenXml.ExcelWorksheet]$ws = $pkg | Add-WorkSheet -WorkSheetname $WorkSheetname -NoClobber:$NoClobber -ClearSheet:$ClearSheet #Add worksheet doesn't take any action for -noClobber foreach ($format in $ConditionalFormat ) { $target = "Add$($format.Formatter)" $rule = ($ws.ConditionalFormatting).PSObject.Methods[$target].Invoke($format.Range, $format.IconType) $rule.Reverse = $format.Reverse } - if ($append) { - $headerRange = $ws.Dimension.Address -replace "\d+$","1" + if ($append) { + $headerRange = $ws.Dimension.Address -replace "\d+$", "1" #if there is a title or anything else above the header row, specifying StartRow will skip it. - if ($StartRow -ne 1) {$headerRange = $headerRange -replace "1","$StartRow"} + if ($StartRow -ne 1) {$headerRange = $headerRange -replace "1", "$StartRow"} #$script:Header = $ws.Cells[$headerrange].Value - #using a slightly odd syntax otherwise header ends up as a 2D array - $ws.Cells[$headerRange].Value | foreach -Begin {$Script:header = @()} -Process {$Script:header += $_ } - $row = $ws.Dimension.Rows + #using a slightly odd syntax otherwise header ends up as a 2D array + $ws.Cells[$headerRange].Value | foreach -Begin {$Script:header = @()} -Process {$Script:header += $_ } + $row = $ws.Dimension.Rows Write-Debug -Message ("Appending: headers are " + ($script:Header -join ", ") + "Start row $row") } - elseif($Title) { #Can only add a title if not appending + elseif ($Title) { + #Can only add a title if not appending $Row = $StartRow Add-Title - $Row ++ ; $startRow ++ + $Row ++ ; $startRow ++ } else { $Row = $StartRow @@ -586,7 +596,8 @@ $pattern = 'string|bool|byte|char|decimal|double|float|int|long|sbyte|short|uint|ulong|ushort' } Catch { - if ($AlreadyExists) { #Is this set anywhere ? + if ($AlreadyExists) { + #Is this set anywhere ? throw "Failed exporting worksheet '$WorkSheetname' to '$Path': The worksheet '$WorkSheetname' already exists." } else { @@ -596,76 +607,76 @@ } Process { - if ($TargetData) { - Try { - if ($firstTimeThru) { - $firstTimeThru = $false - $isDataTypeValueType = $TargetData.GetType().name -match $pattern - Write-Debug "DataTypeName is '$($TargetData.GetType().name)' isDataTypeValueType '$isDataTypeValueType'" - } - - if ($isDataTypeValueType) { - $ColumnIndex = $StartColumn - - Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData - - $ColumnIndex += 1 - $Row += 1 - } - else { - #region Add headers - if (-not $script:Header) { - $ColumnIndex = $StartColumn - $script:Header = $TargetData.PSObject.Properties.Name | Where-Object {$_ -notin $ExcludeProperty} - - if ($NoHeader) { - # Don't push the headers to the spread sheet - $Row -= 1 - } - else { - foreach ($Name in $script:Header) { - $ws.Cells[$Row, $ColumnIndex].Value = $Name - Write-Verbose "Cell '$Row`:$ColumnIndex' add header '$Name'" - $ColumnIndex += 1 - } - } + if ($TargetData) { + Try { + if ($firstTimeThru) { + $firstTimeThru = $false + $isDataTypeValueType = $TargetData.GetType().name -match $pattern + Write-Debug "DataTypeName is '$($TargetData.GetType().name)' isDataTypeValueType '$isDataTypeValueType'" } - #endregion - $Row += 1 - $ColumnIndex = $StartColumn + if ($isDataTypeValueType) { + $ColumnIndex = $StartColumn - foreach ($Name in $script:Header) { - #region Add non header values - Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData.$Name + Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData $ColumnIndex += 1 + $Row += 1 + } + else { + #region Add headers + if (-not $script:Header) { + $ColumnIndex = $StartColumn + $script:Header = $TargetData.PSObject.Properties.Name | Where-Object {$_ -notin $ExcludeProperty} + + if ($NoHeader) { + # Don't push the headers to the spread sheet + $Row -= 1 + } + else { + foreach ($Name in $script:Header) { + $ws.Cells[$Row, $ColumnIndex].Value = $Name + Write-Verbose "Cell '$Row`:$ColumnIndex' add header '$Name'" + $ColumnIndex += 1 + } + } + } #endregion + + $Row += 1 + $ColumnIndex = $StartColumn + + foreach ($Name in $script:Header) { + #region Add non header values + Add-CellValue -TargetCell $ws.Cells[$Row, $ColumnIndex] -CellValue $TargetData.$Name + + $ColumnIndex += 1 + #endregion + } } } + Catch { + throw "Failed exporting worksheet '$WorkSheetname' to '$Path': $_" + } } - Catch { - throw "Failed exporting worksheet '$WorkSheetname' to '$Path': $_" - } - } } End { Try { if ($AutoNameRange) { if (-not $script:header) { - $headerRange = $ws.Dimension.Address -replace "\d+$","1" - #if there is a title or anything else above the header row, specifying StartRow will skip it. - if ($StartRow -ne 1) {$headerRange = $headerRange -replace "1","$StartRow"} - #using a slightly odd syntax otherwise header ends up as a 2D array - $ws.Cells[$headerRange].Value | foreach -Begin {$Script:header = @()} -Process {$Script:header += $_ } - } + $headerRange = $ws.Dimension.Address -replace "\d+$", "1" + #if there is a title or anything else above the header row, specifying StartRow will skip it. + if ($StartRow -ne 1) {$headerRange = $headerRange -replace "1", "$StartRow"} + #using a slightly odd syntax otherwise header ends up as a 2D array + $ws.Cells[$headerRange].Value | foreach -Begin {$Script:header = @()} -Process {$Script:header += $_ } + } $totalRows = $ws.Dimension.End.Row $totalColumns = $ws.Dimension.Columns foreach ($c in 0..($totalColumns - 1)) { $targetRangeName = "$($script:Header[$c])" $targetColumn = $c + $StartColumn - $theCell = $ws.Cells[($startrow+1), $targetColumn, $totalRows , $targetColumn ] + $theCell = $ws.Cells[($startrow + 1), $targetColumn, $totalRows , $targetColumn ] $ws.Names.Add($targetRangeName, $theCell) | Out-Null if ([OfficeOpenXml.FormulaParsing.ExcelUtilities.ExcelAddressUtil]::IsValidAddress($targetRangeName)) { @@ -675,7 +686,7 @@ } if ($Title) { - $startAddress = $ws.Dimension.Start.address -replace "$($ws.Dimension.Start.row)`$", "$($ws.Dimension.Start.row + 1)" + $startAddress = $ws.Dimension.Start.address -replace "$($ws.Dimension.Start.row)`$", "$($ws.Dimension.Start.row + 1)" } else { $startAddress = $ws.Dimension.Start.Address @@ -702,18 +713,21 @@ $tbl = $ws.Tables.Add($targetRange, $TableName) $tbl.TableStyle = $TableStyle } + + $PivotTableStartCell = "A1" + if($PivotFilter) {$PivotTableStartCell = "A3"} if ($PivotTableDefinition) { foreach ($item in $PivotTableDefinition.GetEnumerator()) { $targetName = $item.Key $pivotTableName = $targetName #+ 'PivotTable' #Make sure the Pivot table sheet doesn't already exist - try { $pkg.Workbook.Worksheets.Delete( $pivotTableName) } catch {} + try { $pkg.Workbook.Worksheets.Delete( $pivotTableName) } catch {} $wsPivot = $pkg | Add-WorkSheet -WorkSheetname $pivotTableName -NoClobber:$NoClobber $pivotTableDataName = $targetName + 'PivotTableData' if (!$item.Value.SourceWorkSheet) { - $pivotTable = $wsPivot.PivotTables.Add($wsPivot.Cells['A1'], $ws.Cells[$dataRange], $pivotTableDataName) + $pivotTable = $wsPivot.PivotTables.Add($wsPivot.Cells[$PivotTableStartCell], $ws.Cells[$dataRange], $pivotTableDataName) } else { $workSheet = Find-WorkSheet $item.Value.SourceWorkSheet @@ -722,7 +736,7 @@ $targetStartAddress = $workSheet.Dimension.Start.Address $targetDataRange = "{0}:{1}" -f $targetStartAddress, $workSheet.Dimension.End.Address - $pivotTable = $wsPivot.PivotTables.Add($wsPivot.Cells['A1'], $workSheet.Cells[$targetDataRange], $pivotTableDataName) + $pivotTable = $wsPivot.PivotTables.Add($wsPivot.Cells[$PivotTableStartCell], $workSheet.Cells[$targetDataRange], $pivotTableDataName) } } @@ -768,26 +782,33 @@ $chart = $wsPivot.Drawings.AddChart('PivotChart', $ChartType, $pivotTable) $chart.SetPosition(0, 0, 4, 0) #Changed position to top row, next to a chart which doesn't pivot on columns $chart.SetSize(600, 400) - $chart.DataLabel.ShowCategory = [boolean]$item.value.ShowCategory - $chart.DataLabel.ShowPercent = [boolean]$item.value.ShowPercent - if ([boolean]$item.value.NoLegend) {$chart.Legend.Remove()} - if ($item.value.ChartTitle) {$chart.Title.Text = $item.value.chartTitle} + if ($chart.DataLabel) { + $chart.DataLabel.ShowCategory = [boolean]$item.value.ShowCategory + $chart.DataLabel.ShowPercent = [boolean]$item.value.ShowPercent + } + if ([boolean]$item.value.NoLegend) {$chart.Legend.Remove()} + if ($item.value.ChartTitle) {$chart.Title.Text = $item.value.chartTitle} } } + + if($item.Value.NoTotalsInPivot) { + $pivotTable.RowGrandTotals = $false + } } } - if ($IncludePivotTable -or $IncludePivotChart) { #changed so -includePivotChart Implies -includePivotTable. + if ($IncludePivotTable -or $IncludePivotChart) { + #changed so -includePivotChart Implies -includePivotTable. $pivotTableName = $WorkSheetname + 'PivotTable' #Make sure the Pivot table sheet doesn't already exist - try { $pkg.Workbook.Worksheets.Delete( $pivotTableName) } catch {} + try { $pkg.Workbook.Worksheets.Delete( $pivotTableName) } catch {} $wsPivot = $pkg | Add-WorkSheet -WorkSheetname $pivotTableName -NoClobber:$NoClobber $wsPivot.View.TabSelected = $true $pivotTableDataName = $WorkSheetname + 'PivotTableData' - $pivotTable = $wsPivot.PivotTables.Add($wsPivot.Cells['A1'], $ws.Cells[$dataRange], $pivotTableDataName) + $pivotTable = $wsPivot.PivotTables.Add($wsPivot.Cells[$PivotTableStartCell], $ws.Cells[$dataRange], $pivotTableDataName) if ($PivotRows) { foreach ($Row in $PivotRows) { @@ -819,11 +840,17 @@ } } + if($NoTotalsInPivot) { + $pivotTable.RowGrandTotals = $false + } + if ($IncludePivotChart) { $chart = $wsPivot.Drawings.AddChart('PivotChart', $ChartType, $pivotTable) - $chart.DataLabel.ShowCategory = $ShowCategory - $chart.DataLabel.ShowPercent = $ShowPercent - $chart.SetPosition(0,26,2,26) # if Pivot table is rows+data only it will be 2 columns wide if has pivot columns we don't know how wide it will be + if ($chart.DataLabel) { + $chart.DataLabel.ShowCategory = $ShowCategory + $chart.DataLabel.ShowPercent = $ShowPercent + } + $chart.SetPosition(0, 26, 2, 26) # if Pivot table is rows+data only it will be 2 columns wide if has pivot columns we don't know how wide it will be if ($NoLegend) { $chart.Legend.Remove() } @@ -831,6 +858,14 @@ } } + if($pivotTable -and $PivotFilter) { + + foreach($pFilter in $PivotFilter) { + $null = $pivotTable.PageFields.Add($pivotTable.Fields[$pFilter]) + } + } + + if ($Password) { $ws.Protection.SetPassword($Password) } @@ -962,7 +997,30 @@ $pkg } else { + if ($ReturnRange) { + $ws.Dimension.Address + } + + + $pkg.Save() + + if ($ReZip) { + write-verbose "Re-Zipping $($pkg.file) using .NET ZIP library" + $zipAssembly = "System.IO.Compression.Filesystem" + try { + Add-Type -assembly $zipAssembly -ErrorAction stop + } catch { + write-error "The -ReZip parameter requires .NET Framework 4.5 or later to be installed. Recommend to install Powershell v4+" + continue + } + + $TempZipPath = Join-Path -path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName()) + [io.compression.zipfile]::ExtractToDirectory($pkg.File,$TempZipPath) | Out-Null + Remove-Item $pkg.File -Force + [io.compression.zipfile]::CreateFromDirectory($TempZipPath,$pkg.File) | Out-Null + } + $pkg.Dispose() if ($Show) { @@ -990,11 +1048,12 @@ function New-PivotTableDefinition { [Switch]$NoLegend, [Switch]$ShowCategory, [Switch]$ShowPercent, - [String]$ChartTitle + [String]$ChartTitle, + [Switch]$NoTotalsInPivot ) $parameters = @{} + $PSBoundParameters $parameters.Remove('PivotTableName') - @{$PivotTableName=$parameters} + @{$PivotTableName = $parameters} } \ No newline at end of file diff --git a/GetExcelTable.ps1 b/GetExcelTable.ps1 new file mode 100644 index 0000000..e1aacc0 --- /dev/null +++ b/GetExcelTable.ps1 @@ -0,0 +1,104 @@ +Function Get-ExcelTableName { + Param ( + $Path, + $WorksheetName + ) + + $Path = (Resolve-Path $Path).ProviderPath + $Stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path, 'Open', 'Read', 'ReadWrite' + + $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Stream + + if ($WorksheetName) { + $Worksheet = $Excel.Workbook.Worksheets[$WorkSheetName] + } else { + $Worksheet = $Excel.Workbook.Worksheets | Select-Object -First 1 + } + + foreach($TableName in $Worksheet.Tables.Name) { + [PSCustomObject][Ordered]@{ + WorksheetName=$Worksheet.Name + TableName=$TableName + } + } + + $Stream.Close() + $Stream.Dispose() + $Excel.Dispose() + $Excel = $null +} + +Function Get-ExcelTable { + Param ( + $Path, + $TableName, + $WorksheetName + ) + + $Path = (Resolve-Path $Path).ProviderPath + $Stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path, 'Open', 'Read', 'ReadWrite' + + $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Stream + + if ($WorksheetName) { + $Worksheet = $Excel.Workbook.Worksheets[$WorkSheetName] + } else { + $Worksheet = $Excel.Workbook.Worksheets | Select-Object -First 1 + } + + if($TableName) { + $Table = $Worksheet.Tables[$TableName] + } else { + $Table = $Worksheet.Tables | Select-Object -First 1 + } + + $rowCount = $Table.Address.Rows + $colCount = $Table.Address.Columns + + $digits = "0123456789".ToCharArray() + + $start, $end=$Table.Address.Address.Split(':') + + $pos=$start.IndexOfAny($digits) + [int]$startCol=ConvertFrom-ExcelColumnName $start.Substring(0,$pos) + [int]$startRow=$start.Substring($pos) + + $propertyNames = for($col=$startCol; $col -lt ($startCol+$colCount); $col+= 1) { + $Worksheet.Cells[$startRow, $col].value + } + + $startRow++ + for($row=$startRow; $row -lt ($startRow+$rowCount); $row += 1) { + $nr=[ordered]@{} + $c=0 + for($col=$startCol; $col -lt ($startCol+$colCount); $col+= 1) { + $nr.($propertyNames[$c]) = $Worksheet.Cells[$row, $col].value + $c++ + } + [pscustomobject]$nr + } + + $Stream.Close() + $Stream.Dispose() + $Excel.Dispose() + $Excel = $null +} + +function ConvertFrom-ExcelColumnName { + param($columnName) + + $sum=0 + $columnName.ToCharArray() | + ForEach { + $sum*=26 + $sum+=[char]$_.tostring().toupper()-[char]'A'+1 + } + $sum +} + +cls + +ipmo .\ImportExcel.psd1 -Force + +#Get-ExcelTableName .\testTable.xlsx | Get-ExcelTable .\testTable.xlsx +Get-ExcelTable .\testTable.xlsx Table3 \ No newline at end of file diff --git a/ImportExcel.Tests.ps1 b/ImportExcel.Tests.ps1 index 91d8042..faacee7 100644 --- a/ImportExcel.Tests.ps1 +++ b/ImportExcel.Tests.ps1 @@ -2070,4 +2070,15 @@ Context 'special cases' { } } } +} + +Context 'General Tests' { + in $TestDrive { + Describe 'Get Help' { + it 'New-Plot' { + #Get-Help : Unable to find type [PSPlot]. + {Help New-Plot} | Should -Not -Throw + } + } + } } \ No newline at end of file diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index 88e9c1f..807d835 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -4,7 +4,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. -ModuleVersion = '4.0.4' +ModuleVersion = '4.0.13' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' @@ -19,7 +19,10 @@ CompanyName = 'Doug Finke' Copyright = 'c 2015 All rights reserved.' # Description of the functionality provided by this module -Description = 'PowerShell module to import/export Excel spreadsheets, without Excel' + Description = @' +PowerShell module to import/export Excel spreadsheets, without Excel. +Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq +'@ # Minimum version of the Windows PowerShell engine required by this module # PowerShellVersion = '' diff --git a/ImportExcel.psm1 b/ImportExcel.psm1 index 250a659..d88e8ae 100644 --- a/ImportExcel.psm1 +++ b/ImportExcel.psm1 @@ -31,14 +31,14 @@ . $PSScriptRoot\SetFormat.ps1 . $PSScriptRoot\TrackingUtils.ps1 . $PSScriptRoot\Update-FirstObjectProperties.ps1 +. $PSScriptRoot\ConvertExcelToImageFile.ps1 -New-Alias -Name Use-ExcelData -Value "ConvertFrom-ExcelData" +New-Alias -Name Use-ExcelData -Value "ConvertFrom-ExcelData" -Force if ($PSVersionTable.PSVersion.Major -ge 5) { . $PSScriptRoot\Plot.ps1 Function New-Plot { - [OutputType([PSPlot])] Param() [PSPlot]::new() @@ -237,7 +237,7 @@ Function Import-Excel { Param ( [Alias('FullName')] [Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Position=0, Mandatory)] - [ValidateScript({(Test-Path -Path $_ -PathType Leaf) -and ($_ -match '.xls$|.xlsx$')})] + [ValidateScript( {(Test-Path -Path $_ -PathType Leaf) -and ($_ -match '.xls$|.xlsx$|.xlsm$')})] [String]$Path, [Alias('Sheet')] [Parameter(Position=1)] diff --git a/Install.ps1 b/Install.ps1 index a827fce..66f7089 100644 --- a/Install.ps1 +++ b/Install.ps1 @@ -20,14 +20,19 @@ Begin { Write-Verbose "$ModuleName module installation started" $Files = @( + 'AddConditionalFormatting.ps1', 'Charting.ps1', + 'ColorCompletion.ps1', 'ConvertFromExcelData.ps1', 'ConvertFromExcelToSQLInsert.ps1', + 'ConvertExcelToImageFile.ps1', 'ConvertToExcelXlsx.ps1', 'Copy-ExcelWorkSheet.ps1', 'EPPlus.dll', + 'Export-charts.ps1', 'Export-Excel.ps1', 'Export-ExcelSheet.ps1', + 'formatting.ps1', 'Get-ExcelColumnName.ps1', 'Get-ExcelSheetInfo.ps1', 'Get-ExcelWorkbookInfo.ps1', @@ -43,9 +48,14 @@ Begin { 'New-ConditionalText.ps1', 'New-ExcelChart.ps1', 'New-PSItem.ps1', + 'Open-ExcelPackage.ps1', 'Pivot.ps1', - 'Plot.ps1', + 'plot.ps1', + 'Send-SqlDataToExcel.ps1', 'Set-CellStyle.ps1', + 'Set-Column.ps1', + 'Set-Row.ps1', + 'SetFormat.ps1', 'TrackingUtils.ps1', 'Update-FirstObjectProperties.ps1' ) diff --git a/InstallModule.ps1 b/InstallModule.ps1 index e4431ff..6877963 100644 --- a/InstallModule.ps1 +++ b/InstallModule.ps1 @@ -27,6 +27,7 @@ Begin { 'ColorCompletion.ps1', 'ConvertFromExcelData.ps1', 'ConvertFromExcelToSQLInsert.ps1', + 'ConvertExcelToImageFile.ps1', 'ConvertToExcelXlsx.ps1', 'Copy-ExcelWorkSheet.ps1', 'Export-Charts.ps1', @@ -49,7 +50,10 @@ Begin { 'Open-ExcelPackage.ps1', 'Pivot.ps1', 'Plot.ps1', + 'Send-SQLDataToExcel.ps1', 'Set-CellStyle.ps1', + 'Set-Column.ps1', + 'Set-Row.ps1', 'SetFormat.ps1', 'TrackingUtils.ps1', 'Update-FirstObjectProperties.ps1' diff --git a/README.md b/README.md index 03e0c1c..340d773 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,9 @@ This PowerShell Module allows you to read and write Excel files without installi ![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/testimonial.png) +# How to Vidoes +* [PowerShell Excel Module - ImportExcel](https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq) + Installation - #### [PowerShell V5](https://www.microsoft.com/en-us/download/details.aspx?id=50395) and Later @@ -27,6 +30,91 @@ iex (new-object System.Net.WebClient).DownloadString('https://raw.github.com/dfi ``` # What's new + +#### 4/10/2018 +Thanks to the community yet again, [ili101](https://github.com/ili101) for fixes and features +- Removed `[PSPlot]` as OutputType. Fixes it throwing an error + +#### 4/10/2018 +-New parameter `-ReZip`. It ReZips the xlsx so it can be imported to PowerBI + +Thanks to [Justin Grote](https://github.com/JustinGrote) for finding and fixing the error that Excel files created do not import to PowerBI online. Plus, thank you to [CrashM](https://github.com/CrashM) for confirming the fix. + +Super helpful! + +#### 3/31/2018 +- Updated `Set-Format` + * Added parameters to set borders for cells, including top, bottm, left and right + * Added parameters to set `value` and `formula` + +```powershell +$data = @" +From,To,RDollars,RPercent,MDollars,MPercent,Revenue,Margin +Atlanta,New York,3602000,.0809,955000,.09,245,65 +New York,Washington,4674000,.105,336000,.03,222,16 +Chicago,New York,4674000,.0804,1536000,.14,550,43 +New York,Philadelphia,12180000,.1427,-716000,-.07,321,-25 +New York,San Francisco,3221000,.0629,1088000,.04,436,21 +New York,Phoneix,2782000,.0723,467000,.10,674,33 +"@ +``` + +![](https://github.com/dfinke/ImportExcel/blob/master/images/CustomReport.png?raw=true) + + +- Added `-PivotFilter` parameter, allows you to set up a filter so you can drill down into a subset of the overall dataset. + +```powershell +$data =@" +Region,Area,Product,Units,Cost +North,A1,Apple,100,.5 +South,A2,Pear,120,1.5 +East,A3,Grape,140,2.5 +West,A4,Banana,160,3.5 +North,A1,Pear,120,1.5 +North,A1,Grape,140,2.5 +"@ +``` + +![](https://github.com/dfinke/ImportExcel/blob/master/images/PivotTableFilter.png?raw=true) + + +#### 3/14/2018 +- Thank you to [James O'Neill](https://twitter.com/jamesoneill), fixed bugs with ChangeDatabase parameter which would prevent it working + +#### +* Added -Force to New-Alias +* Add example to set the background color of a column +* Supports excluding Row Grand Totals for PivotTables +* Allow xlsm files to be read +* Fix `Set-Column.ps1`, `Set-Row.ps1`, `SetFormat.ps1`, `formatting.ps1` **$falsee** and **$BorderRound** +#### 1/1/2018 +* Added switch `[Switch]$NoTotalsInPivot`. Allows hiding of the row totals in the pivot table. +Thanks you to [jameseholt](https://github.com/jameseholt) for the request. + +```powershell + get-process | where Company | select Company, Handles, WorkingSet | + export-excel C:\temp\testColumnGrand.xlsx ` + -Show -ClearSheet -KillExcel ` + -IncludePivotTable -PivotRows Company -PivotData @{"Handles"="average"} -NoTotalsInPivot +``` + +* Fixed when using certain a `ChartType` for the Pivot Table Chart, would throw an error +* Fixed - when you specify a file, and the directory does not exit, it now creates it + +#### 11/23/2017 +More great additions and thanks to [James O'Neill](https://twitter.com/jamesoneill) + +* Added `Convert-XlRangeToImage` Gets the specified part of an Excel file and exports it as an image +* Fixed a typo in the message at line 373. +* Now catch an attempt to both clear the sheet and append to it. +* Fixed some issues when appending to sheets where the header isn't in row 1 or the data doesn't start in column 1. +* Added support for more settings when creating a pivot chart. +* Corrected a typo PivotTableName was PivtoTableName in definition of New-PivotTableDefinition +* Add-ConditionalFormat and Set-Format added to the parameters so each has the choice of working more like the other. +* Added Set-Row and Set-Column - fill a formula down or across. +* Added Send-SQLDataToExcel. Insert a rowset and then call Export-Excel for ranges, charts, pivots etc + #### 10/30/2017 Huge thanks to [James O'Neill](https://twitter.com/jamesoneill). PowerShell aficionado. He always brings a flare when working with PowerShell. This is no exception. diff --git a/RemoveWorksheet.ps1 b/RemoveWorksheet.ps1 new file mode 100644 index 0000000..0b2c06b --- /dev/null +++ b/RemoveWorksheet.ps1 @@ -0,0 +1,35 @@ +Function Remove-WorkSheet { + Param ( + $Path, + $WorksheetName + ) + + $Path = (Resolve-Path $Path).ProviderPath + + $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $Path + + $workSheet = $Excel.Workbook.Worksheets[$WorkSheetName] + + if($workSheet) { + if($Excel.Workbook.Worksheets.Count -gt 1) { + $Excel.Workbook.Worksheets.Delete($workSheet) + } else { + throw "Cannot delete $WorksheetName. A workbook must contain at least one visible worksheet" + } + + } else { + throw "$WorksheetName not found" + } + + $Excel.Save() + $Excel.Dispose() +} + +cls + +ipmo .\ImportExcel.psd1 -Force + +$names = Get-ExcelSheetInfo C:\Temp\testDelete.xlsx +$names | % { Remove-WorkSheet C:\Temp\testDelete.xlsx $_.Name} + +##Remove-WorkSheet C:\Temp\testDelete.xlsx sheet6 \ No newline at end of file diff --git a/Set-Column.ps1 b/Set-Column.ps1 index f195cf8..32da5bb 100644 --- a/Set-Column.ps1 +++ b/Set-Column.ps1 @@ -4,20 +4,20 @@ Adds a column to the existing data area in an Excel sheet, fills values and sets formatting .DESCRIPTION Set-Column takes a value which is either string containing a value or formula or a scriptblock - which evaluates to a string, and optionally a column number and fills that value down the column. - A column name can be specified and the new column can be made a named range. - The column can be formatted. + which evaluates to a string, and optionally a column number and fills that value down the column. + A column name can be specified and the new column can be made a named range. + The column can be formatted. .Example C:> Set-Column -Worksheet $ws -Heading "WinsToFastLaps" -Value {"=E$row/C$row"} -Column 7 -AutoSize -AutoNameRange Here $WS already contains a worksheet which contains counts of races won and fastest laps recorded by racing drivers (in columns C and E) - Set-Column specifies that Column 7 should have a heading of "WinsToFastLaps" and the data cells should contain =E2/C2 , =E3/C3 - the data celss should become a named range, which will also be "WinsToFastLaps" the column width will be set automatically - + Set-Column specifies that Column 7 should have a heading of "WinsToFastLaps" and the data cells should contain =E2/C2 , =E3/C3 + the data celss should become a named range, which will also be "WinsToFastLaps" the column width will be set automatically + #> [cmdletbinding()] Param ( [Parameter(ParameterSetName="Package",Mandatory=$true)] - [OfficeOpenXml.ExcelPackage]$ExcelPackage, + [OfficeOpenXml.ExcelPackage]$ExcelPackage, #Sheet to update [Parameter(ParameterSetName="Package")] $Worksheetname = "Sheet1", @@ -27,7 +27,7 @@ #Column to fill down - first column is 1. 0 will be interpreted as first unused column $Column = 0 , [Int]$StartRow , - #value, formula or script block for to fill in. Script block can use $row, $column [number], $ColumnName [letter(s)], $startRow, $startColumn, $endRow, $endColumn + #value, formula or script block for to fill in. Script block can use $row, $column [number], $ColumnName [letter(s)], $startRow, $startColumn, $endRow, $endColumn [parameter(Mandatory=$true)] $Value , #Optional column heading @@ -80,41 +80,41 @@ [Switch]$AutoNameRange, [switch]$PassThru ) - #if we were passed a package object and a worksheet name , get the worksheet. - if ($ExcelPackage) {$Worksheet = $ExcelPackage.Workbook.Worksheets[$Worksheetname] } - - #In a script block to build a formula, we may want any of corners or the columnname, + #if we were passed a package object and a worksheet name , get the worksheet. + if ($ExcelPackage) {$Worksheet = $ExcelPackage.Workbook.Worksheets[$Worksheetname] } + + #In a script block to build a formula, we may want any of corners or the columnname, #if column and startrow aren't specified, assume first unused column, and first row if (-not $StartRow) {$startRow = $Worksheet.Dimension.Start.Row } - $StartColumn = $Worksheet.Dimension.Start.Column + $StartColumn = $Worksheet.Dimension.Start.Column $endColumn = $Worksheet.Dimension.End.Column - $endRow = $Worksheet.Dimension.End.Row - if ($Column -lt 2 ) {$Column = $endColumn + 1 } + $endRow = $Worksheet.Dimension.End.Row + if ($Column -lt 2 ) {$Column = $endColumn + 1 } $ColumnName = [OfficeOpenXml.ExcelCellAddress]::new(1,$column).Address -replace "1","" - Write-Verbose -Message "Updating Column $ColumnName" + Write-Verbose -Message "Updating Column $ColumnName" #If there is a heading, insert it and use it as the name for a range (if we're creating one) if ($Heading) { - $Worksheet.Cells[$StartRow, $Column].Value = $heading - $startRow ++ + $Worksheet.Cells[$StartRow, $Column].Value = $heading + $startRow ++ if ($AutoNameRange) { $Worksheet.Names.Add( $heading, ($Worksheet.Cells[$startrow, $Column, $endRow, $Column]) ) | Out-Null } - } + } #Fill in the data if ($value) { foreach ($row in ($StartRow.. $endRow)) { - if ($Value -is [scriptblock]) { #re-create the script block otherwise variables from this function are out of scope. - $cellData = & ([scriptblock]::create( $Value )) - Write-Verbose -Message $cellData + if ($Value -is [scriptblock]) { #re-create the script block otherwise variables from this function are out of scope. + $cellData = & ([scriptblock]::create( $Value )) + Write-Verbose -Message $cellData } - else { $cellData = $Value} + else { $cellData = $Value} if ($cellData -match "^=") { $Worksheet.Cells[$Row, $Column].Formula = $cellData } - else { $Worksheet.Cells[$Row, $Column].Value = $cellData } - if ($cellData -is [datetime]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = 'm/d/yy h:mm' } - }} - #region Apply formatting + else { $Worksheet.Cells[$Row, $Column].Value = $cellData } + if ($cellData -is [datetime]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = 'm/d/yy h:mm' } + }} + #region Apply formatting if ($Underline) { $Worksheet.Column( $Column).Style.Font.UnderLine = $true $Worksheet.Column( $Column).Style.Font.UnderLineType = $UnderLineType - } + } if ($Bold) { $Worksheet.Column( $Column).Style.Font.Bold = $true } if ($Italic) { $Worksheet.Column( $Column).Style.Font.Italic = $true } if ($StrikeThru) { $Worksheet.Column( $Column).Style.Font.Strike = $true } @@ -123,9 +123,9 @@ if ($TextRotation) { $Worksheet.Column( $Column).Style.TextRotation = $TextRotation } if ($WrapText) { $Worksheet.Column( $Column).Style.WrapText = $true } if ($HorizontalAlignment) { $Worksheet.Column( $Column).Style.HorizontalAlignment = $HorizontalAlignment} - if ($VerticalAlignment) { $Worksheet.Column( $Column).Style.VerticalAlignment = $VerticalAlignment } + if ($VerticalAlignment) { $Worksheet.Column( $Column).Style.VerticalAlignment = $VerticalAlignment } if ($FontColor) { $Worksheet.Column( $Column).Style.Font.Color.SetColor( $FontColor ) } - if ($BorderRound) { $Worksheet.Column( $Column).Style.Border.BorderAround( $BorderAround ) } + if ($BorderAround) { $Worksheet.Column( $Column).Style.Border.BorderAround( $BorderAround ) } if ($BackgroundColor) { $Worksheet.Column( $Column).Style.Fill.PatternType = $BackgroundPattern $Worksheet.Column( $Column).Style.Fill.BackgroundColor.SetColor($BackgroundColor ) @@ -133,7 +133,7 @@ } if ($Autosize) { $Worksheet.Column( $Column).AutoFit() } elseif ($Width) { $Worksheet.Column( $Column).Width = $Width } - #endregion + #endregion #return the new data if -passthru was specified. - if ($passThru) { $Worksheet.Column( $Column)} + if ($passThru) { $Worksheet.Column( $Column)} } \ No newline at end of file diff --git a/Set-Row.ps1 b/Set-Row.ps1 index f1e43be..e66850e 100644 --- a/Set-Row.ps1 +++ b/Set-Row.ps1 @@ -1,40 +1,40 @@ Function Set-Row { <# -.Synopsis +.Synopsis Fills values into a row in a Excel spreadsheet -.Description - Set-Row accepts either a Worksheet object or an Excel package object returned by Export-Excel and the name of a sheet, - and inserts the chosen contents into a row of the sheet. - The contents can be a constant "42" , a formula or a script block which is converted into a constant or formula. - The first cell of the row can optional be given a heading. -.Example - Set-row -Worksheet $ws -Heading Total -Value {"=sum($columnName`2:$columnName$endrow)" } - - $Ws contains a worksheet object, and no Row number is specified so Set-Row will select the next row after the end of the data in the sheet - The first cell will contain "Total", and each other cell will contain - =Sum(xx2:xx99) - where xx is the column name, and 99 is the last row of data. - Note the use of `2 to Prevent 2 becoming part of the variable "ColumnName" - The script block can use $row, $column, $ColumnName, $startRow/Column $endRow/Column +.Description + Set-Row accepts either a Worksheet object or an Excel package object returned by Export-Excel and the name of a sheet, + and inserts the chosen contents into a row of the sheet. + The contents can be a constant "42" , a formula or a script block which is converted into a constant or formula. + The first cell of the row can optional be given a heading. +.Example + Set-row -Worksheet $ws -Heading Total -Value {"=sum($columnName`2:$columnName$endrow)" } + + $Ws contains a worksheet object, and no Row number is specified so Set-Row will select the next row after the end of the data in the sheet + The first cell will contain "Total", and each other cell will contain + =Sum(xx2:xx99) - where xx is the column name, and 99 is the last row of data. + Note the use of `2 to Prevent 2 becoming part of the variable "ColumnName" + The script block can use $row, $column, $ColumnName, $startRow/Column $endRow/Column + - #> [cmdletbinding()] Param ( #An Excel package object - e.g. from Export-Excel -passthru - requires a sheet name [Parameter(ParameterSetName="Package",Mandatory=$true)] - [OfficeOpenXml.ExcelPackage]$ExcelPackage, - #the name to update in the package + [OfficeOpenXml.ExcelPackage]$ExcelPackage, + #the name to update in the package [Parameter(ParameterSetName="Package")] $Worksheetname = "Sheet1", - #A worksheet object + #A worksheet object [Parameter(ParameterSetName="sheet",Mandatory=$true)] [OfficeOpenXml.Excelworksheet] $Worksheet, #Row to fill right - first row is 1. 0 will be interpreted as first unused row $Row = 0 , - #Position in the row to start from + #Position in the row to start from [Int]$StartColumn, - #value, formula or script block for to fill in. Script block can use $row, $column [number], $ColumnName [letter(s)], $startRow, $startColumn, $endRow, $endColumn + #value, formula or script block for to fill in. Script block can use $row, $column [number], $ColumnName [letter(s)], $startRow, $startColumn, $endRow, $endColumn [parameter(Mandatory=$true)] $Value, #Optional Row heading @@ -78,43 +78,43 @@ #Degrees to rotate text. Up to +90 for anti-clockwise ("upwards"), or to -90 for clockwise. [ValidateRange(-90, 90)] [int]$TextRotation , - #Set cells to a fixed hieght + #Set cells to a fixed hieght [float]$Height, [switch]$PassThru ) - #if we were passed a package object and a worksheet name , get the worksheet. - if ($ExcelPackage) {$Worksheet = $ExcelPackage.Workbook.worksheets[$Worksheetname] } + #if we were passed a package object and a worksheet name , get the worksheet. + if ($ExcelPackage) {$Worksheet = $ExcelPackage.Workbook.worksheets[$Worksheetname] } - #In a script block to build a formula, we may want any of corners or the columnname, + #In a script block to build a formula, we may want any of corners or the columnname, #if row and start column aren't specified assume first unused row, and first column if (-not $StartColumn) {$StartColumn = $Worksheet.Dimension.Start.Column } $startRow = $Worksheet.Dimension.Start.Row + 1 $endColumn = $Worksheet.Dimension.End.Column - $endRow = $Worksheet.Dimension.End.Row + $endRow = $Worksheet.Dimension.End.Row if ($Row -lt 2 ) {$Row = $endRow + 1 } - - Write-Verbose -Message "Updating Row $Row" - #Add a row label + + Write-Verbose -Message "Updating Row $Row" + #Add a row label if ($Heading) { - $Worksheet.Cells[$Row, $StartColumn].Value = $Heading - $StartColumn ++ + $Worksheet.Cells[$Row, $StartColumn].Value = $Heading + $StartColumn ++ } #Fill in the data if ($value) {foreach ($column in ($StartColumn..$EndColumn)) { #We might want the column name in a script block $ColumnName = [OfficeOpenXml.ExcelCellAddress]::new(1,$column).Address -replace "1","" if ($Value -is [scriptblock] ) { - #re-create the script block otherwise variables from this function are out of scope. - $cellData = & ([scriptblock]::create( $Value )) - Write-Verbose -Message $cellData + #re-create the script block otherwise variables from this function are out of scope. + $cellData = & ([scriptblock]::create( $Value )) + Write-Verbose -Message $cellData } - else{$cellData = $Value} + else{$cellData = $Value} if ($cellData -match "^=") { $Worksheet.Cells[$Row, $column].Formula = $cellData } - else { $Worksheet.Cells[$Row, $Column].Value = $cellData } - if ($cellData -is [datetime]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = 'm/d/yy h:mm' } + else { $Worksheet.Cells[$Row, $Column].Value = $cellData } + if ($cellData -is [datetime]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = 'm/d/yy h:mm' } }} - #region Apply formatting + #region Apply formatting if ($Underline) { $worksheet.row( $Row ).Style.Font.UnderLine = $true $worksheet.row( $Row ).Style.Font.UnderLineType = $UnderLineType @@ -130,13 +130,13 @@ if ($VerticalAlignment) { $worksheet.row( $Row ).Style.VerticalAlignment = $VerticalAlignment } if ($Height) { $worksheet.row( $Row ).Height = $Height } if ($FontColor) { $worksheet.row( $Row ).Style.Font.Color.SetColor( $FontColor ) } - if ($BorderRound) { $worksheet.row( $Row ).Style.Border.BorderAround( $BorderAround ) } + if ($BorderAround) { $worksheet.row( $Row ).Style.Border.BorderAround( $BorderAround ) } if ($BackgroundColor) { $worksheet.row( $Row ).Style.Fill.PatternType = $BackgroundPattern $worksheet.row( $Row ).Style.Fill.BackgroundColor.SetColor($BackgroundColor ) if ($PatternColor) { $worksheet.row( $Row ).Style.Fill.PatternColor.SetColor( $PatternColor ) } - } - #endregion + } + #endregion #return the new data if -passthru was specified. - if ($passThru) {$Worksheet.Row($Row)} + if ($passThru) {$Worksheet.Row($Row)} } \ No newline at end of file diff --git a/SetFormat.ps1 b/SetFormat.ps1 index dfe96ff..80d043b 100644 --- a/SetFormat.ps1 +++ b/SetFormat.ps1 @@ -25,8 +25,17 @@ $NumberFormat, #Style of border to draw around the range [OfficeOpenXml.Style.ExcelBorderStyle]$BorderAround, + [System.Drawing.Color]$BorderColor=[System.Drawing.Color]::Black, + [OfficeOpenXml.Style.ExcelBorderStyle]$BorderBottom, + [OfficeOpenXml.Style.ExcelBorderStyle]$BorderTop, + [OfficeOpenXml.Style.ExcelBorderStyle]$BorderLeft, + [OfficeOpenXml.Style.ExcelBorderStyle]$BorderRight, #Colour for the text - if none specified it will be left as it it is [System.Drawing.Color]$FontColor, + #Value for the cell + $Value, + #Formula for the cell + $Formula, #Clear Bold, Italic, StrikeThrough and Underline and set colour to black [switch]$ResetFont, #Make text bold @@ -72,22 +81,22 @@ [switch]$Hidden ) begin { - #Allow Set-Format to take Worksheet and range parameters (like Add Contitional formatting) - convert them to an address - if ($WorkSheet -and $Range) {$Address = $WorkSheet.Cells[$Range] } + #Allow Set-Format to take Worksheet and range parameters (like Add Contitional formatting) - convert them to an address + if ($WorkSheet -and $Range) {$Address = $WorkSheet.Cells[$Range] } } process { if ($Address -is [Array]) { - [void]$PSBoundParameters.Remove("Address") + [void]$PSBoundParameters.Remove("Address") $Address | Set-Format @PSBoundParameters - } + } else { if ($ResetFont) { $Address.Style.Font.Color.SetColor("Black") $Address.Style.Font.Bold = $false $Address.Style.Font.Italic = $false $Address.Style.Font.UnderLine = $false - $Address.Style.Font.Strike = $falsee + $Address.Style.Font.Strike = $false } if ($Underline) { $Address.Style.Font.UnderLine = $true @@ -98,7 +107,31 @@ if ($StrikeThru) {$Address.Style.Font.Strike = $true } if ($FontShift) {$Address.Style.Font.VerticalAlign = $FontShift } if ($FontColor) {$Address.Style.Font.Color.SetColor( $FontColor ) } - if ($BorderRound) {$Address.Style.Border.BorderAround( $BorderAround ) } + + if ($BorderAround) { + $Address.Style.Border.BorderAround($BorderAround, $BorderColor) + } + + if ($BorderBottom) { + $Address.Style.Border.Bottom.Style=$BorderBottom + $Address.Style.Border.Bottom.Color.SetColor($BorderColor) + } + + if ($BorderTop) { + $Address.Style.Border.Top.Style=$BorderTop + $Address.Style.Border.Top.Color.SetColor($BorderColor) + } + + if ($BorderLeft) { + $Address.Style.Border.Left.Style=$BorderLeft + $Address.Style.Border.Left.Color.SetColor($BorderColor) + } + + if ($BorderRight) { + $Address.Style.Border.Right.Style=$BorderRight + $Address.Style.Border.Right.Color.SetColor($BorderColor) + } + if ($NumberFormat) {$Address.Style.Numberformat.Format = $NumberFormat } if ($TextRotation) {$Address.Style.TextRotation = $TextRotation } if ($WrapText) {$Address.Style.WrapText = $true } @@ -123,15 +156,20 @@ } if ($Autosize) { if ($Address -is [OfficeOpenXml.ExcelColumn]) {$Address.AutoFit() } - elseif ($Address -is [OfficeOpenXml.ExcelRange] ) {$Address.AutoFitColumns() } + elseif ($Address -is [OfficeOpenXml.ExcelRange] ) { + $Address.AutoFitColumns() + } else {Write-Warning -Message ("Can autofit a column or a range but not a {0} object" -f ($Address.GetType().name)) } } elseif ($Width) { if ($Address -is [OfficeOpenXml.ExcelColumn]) {$Address.Width = $Width} elseif ($Address -is [OfficeOpenXml.ExcelRange] ) { - ($Address.Start.Column)..($Address.Start.Column + $Address.Columns) | - ForEach-Object {$ws.Column($_).Width = $Width} + ($Address.Start.Column)..($Address.Start.Column + $Address.Columns - 1) | + ForEach-Object { + #$ws.Column($_).Width = $Width + $Address.Worksheet.Column($_).Width = $Width + } } else {Write-Warning -Message ("Can set the width of a column or a range but not a {0} object" -f ($Address.GetType().name)) } } @@ -140,6 +178,14 @@ $Address -is [OfficeOpenXml.ExcelColumn] ) {$Address.Hidden = $True} else {Write-Warning -Message ("Can hide a row or a column but not a {0} object" -f ($Address.GetType().name)) } } + + if ($Value) { + $Address.Value = $Value + } + + if ($Formula) { + $Address.Formula = $Formula + } } } } \ No newline at end of file diff --git a/formatting.ps1 b/formatting.ps1 index 2ec8b58..efc703e 100644 --- a/formatting.ps1 +++ b/formatting.ps1 @@ -1,58 +1,58 @@ Function Add-ConditionalFormatting { <# -.Synopsis - Adds contitional formatting to worksheet -.Example - $excel = $avdata | Export-Excel -Path (Join-path $FilePath "\Machines.XLSX" ) -WorksheetName "Server Anti-Virus" -AutoSize -FreezeTopRow -AutoFilter -PassThru +.Synopsis + Adds contitional formatting to worksheet +.Example + $excel = $avdata | Export-Excel -Path (Join-path $FilePath "\Machines.XLSX" ) -WorksheetName "Server Anti-Virus" -AutoSize -FreezeTopRow -AutoFilter -PassThru - Add-ConditionalFormatting -WorkSheet $excel.Workbook.Worksheets[1] -Address "b":b1048576" -ForeGroundColor "RED" -RuleType ContainsText -ConditionValue "2003" - Add-ConditionalFormatting -WorkSheet $excel.Workbook.Worksheets[1] -Address "i2:i1048576" -ForeGroundColor "RED" -RuleType ContainsText -ConditionValue "Disabled" + Add-ConditionalFormatting -WorkSheet $excel.Workbook.Worksheets[1] -Address "b":b1048576" -ForeGroundColor "RED" -RuleType ContainsText -ConditionValue "2003" + Add-ConditionalFormatting -WorkSheet $excel.Workbook.Worksheets[1] -Address "i2:i1048576" -ForeGroundColor "RED" -RuleType ContainsText -ConditionValue "Disabled" $excel.Workbook.Worksheets[1].Cells["D1:G1048576"].Style.Numberformat.Format = [cultureinfo]::CurrentCulture.DateTimeFormat.ShortDatePattern $excel.Workbook.Worksheets[1].Row(1).style.font.bold = $true - $excel.Save() ; $excel.Dispose() + $excel.Save() ; $excel.Dispose() - Here Export-Excel is called with the -passThru parameter so the Excel Package object is stored in $Excel - The desired worksheet is selected and the then columns B and i are conditially formatted (excluding the top row) to show + Here Export-Excel is called with the -passThru parameter so the Excel Package object is stored in $Excel + The desired worksheet is selected and the then columns B and i are conditially formatted (excluding the top row) to show Fixed formats are then applied to dates in columns D..G and the top row is formatted - Finally the workbook is saved and the Excel closed. + Finally the workbook is saved and the Excel closed. #> Param ( - #The worksheet where the format is to be applied + #The worksheet where the format is to be applied [OfficeOpenXml.ExcelWorksheet]$WorkSheet , - #The area of the worksheet where the format is to be applied + #The area of the worksheet where the format is to be applied [OfficeOpenXml.ExcelAddress]$Range , - #One of the standard named rules - Top / Bottom / Less than / Greater than / Contains etc + #One of the standard named rules - Top / Bottom / Less than / Greater than / Contains etc [Parameter(Mandatory=$true,ParameterSetName="NamedRule",Position=3)] [OfficeOpenXml.ConditionalFormatting.eExcelConditionalFormattingRuleType]$RuleType , - #Text colour for matching objects - [Alias("ForeGroundColour")] + #Text colour for matching objects + [Alias("ForeGroundColour")] [System.Drawing.Color]$ForeGroundColor, - #colour for databar type charts - [Parameter(Mandatory=$true,ParameterSetName="DataBar")] - [Alias("DataBarColour")] + #colour for databar type charts + [Parameter(Mandatory=$true,ParameterSetName="DataBar")] + [Alias("DataBarColour")] [System.Drawing.Color]$DataBarColor, #One of the three-icon set types (e.g. Traffic Lights) - [Parameter(Mandatory=$true,ParameterSetName="ThreeIconSet")] + [Parameter(Mandatory=$true,ParameterSetName="ThreeIconSet")] [OfficeOpenXml.ConditionalFormatting.eExcelconditionalFormatting3IconsSetType]$ThreeIconsSet, #A four-icon set name - [Parameter(Mandatory=$true,ParameterSetName="FourIconSet")] + [Parameter(Mandatory=$true,ParameterSetName="FourIconSet")] [OfficeOpenXml.ConditionalFormatting.eExcelconditionalFormatting4IconsSetType]$FourIconsSet, #A five-icon set name - [Parameter(Mandatory=$true,ParameterSetName="FiveIconSet")] + [Parameter(Mandatory=$true,ParameterSetName="FiveIconSet")] [OfficeOpenXml.ConditionalFormatting.eExcelconditionalFormatting5IconsSetType]$FiveIconsSet, - #A value for the condition (e.g. "2000" if the test is 'lessthan 2000') + #A value for the condition (e.g. "2000" if the test is 'lessthan 2000') [string]$ConditionValue, - #A second value for the conditions like between x and Y + #A second value for the conditions like between x and Y [string]$ConditionValue2, #Background colour for matching items [System.Drawing.Color]$BackgroundColor, #Background pattern for matching items - [OfficeOpenXml.Style.ExcelFillStyle]$BackgroundPattern = [OfficeOpenXml.Style.ExcelFillStyle]::Solid, + [OfficeOpenXml.Style.ExcelFillStyle]$BackgroundPattern = [OfficeOpenXml.Style.ExcelFillStyle]::Solid, #Secondary colour when a background pattern requires it [System.Drawing.Color]$PatternColor, #Sets the numeric format for matching items - $NumberFormat, + $NumberFormat, #Put matching items in bold face [switch]$Bold, #Put matching items in italic @@ -61,27 +61,27 @@ [switch]$Underline, #Strikethrough text of matching items [switch]$StrikeThru - ) + ) - If ($ThreeIconsSet) {$rule = $WorkSheet.ConditionalFormatting.AddThreeIconSet($Range , $ThreeIconsSet)} + If ($ThreeIconsSet) {$rule = $WorkSheet.ConditionalFormatting.AddThreeIconSet($Range , $ThreeIconsSet)} elseif ($FourIconsSet) {$rule = $WorkSheet.ConditionalFormatting.AddFourIconSet( $Range , $FourIconsSet) } elseif ($FiveIconsSet) {$rule = $WorkSheet.ConditionalFormatting.AddFiveIconSet( $Range , $IconType) } elseif ($DataBarColor) {$rule = $WorkSheet.ConditionalFormatting.AddDatabar( $Range , $DataBarColor) } else { $rule = ($WorkSheet.ConditionalFormatting)."Add$RuleType"($Range)} - - if ($ConditionValue -and $RuleType -match "Top|Botom") {$rule.Rank = $ConditionValue } + + if ($ConditionValue -and $RuleType -match "Top|Botom") {$rule.Rank = $ConditionValue } if ($ConditionValue -and $RuleType -match "StdDev") {$rule.StdDev = $ConditionValue } if ($ConditionValue -and $RuleType -match "Than|Equal|Expression") {$rule.Formula = $ConditionValue } if ($ConditionValue -and $RuleType -match "Text|With") {$rule.Text = $ConditionValue } if ($ConditionValue -and $ConditionValue2 -and $RuleType -match "Between") {$rule.Formula = $ConditionValue $rule.Formula2 = $ConditionValue2} - + if ($NumberFormat) {$rule.Style.NumberFormat.Format = $NumberFormat } - if ($Underline) {$rule.Style.Font.Underline = [OfficeOpenXml.Style.ExcelUnderLineType]::Single } - if ($Bold) {$rule.Style.Font.Bold = $true} + if ($Underline) {$rule.Style.Font.Underline = [OfficeOpenXml.Style.ExcelUnderLineType]::Single } + if ($Bold) {$rule.Style.Font.Bold = $true} if ($Italic) {$rule.Style.Font.Italic = $true} - if ($StrikeThru) {$rule.Style.Font.Strike = $true} + if ($StrikeThru) {$rule.Style.Font.Strike = $true} if ($ForeGroundColor) {$rule.Style.Font.Color.color = $ForeGroundColor } if ($BackgroundColor) {$rule.Style.Fill.BackgroundColor.color = $BackgroundColor } if ($BackgroundPattern) {$rule.Style.Fill.PatternType = $BackgroundPattern } @@ -90,14 +90,14 @@ Function Set-Format { <# -.SYNOPSIS - Applies Number, font, alignment and colour formatting to a range of Excel Cells +.SYNOPSIS + Applies Number, font, alignment and colour formatting to a range of Excel Cells .EXAMPLE $sheet.Column(3) | Set-Format -HorizontalAlignment Right -NumberFormat "#,###" Selects column 3 from a sheet object (within a workbook object, which is a child of the ExcelPackage object) and passes it to Set-Format which formats as an integer with comma seperated groups .EXAMPLE - Set-Format -Address $sheet.Cells["E1:H1048576"] -HorizontalAlignment Right -NumberFormat "#,###" - Instead of piping the address in this version specifies a block of cells and applies similar formatting + Set-Format -Address $sheet.Cells["E1:H1048576"] -HorizontalAlignment Right -NumberFormat "#,###" + Instead of piping the address in this version specifies a block of cells and applies similar formatting #> Param ( @@ -105,62 +105,62 @@ Function Set-Format { [Parameter(ValueFromPipeline=$true)] [object[]]$Address , #Number format to apply to cells e.g. "dd/MM/yyyy HH:mm", "£#,##0.00;[Red]-£#,##0.00", "0.00%" , "##/##" , "0.0E+0" etc - [Alias("NFormat")] - $NumberFormat, + [Alias("NFormat")] + $NumberFormat, #Style of border to draw around the range [OfficeOpenXml.Style.ExcelBorderStyle]$BorderAround, - #Colour for the text - if none specified it will be left as it it is + #Colour for the text - if none specified it will be left as it it is [System.Drawing.Color]$FontColor, #Clear Bold, Italic, StrikeThrough and Underline and set colour to black - [switch]$ResetFont, + [switch]$ResetFont, #Make text bold [switch]$Bold, #Make text italic [switch]$Italic, - #Underline the text using the underline style in -underline type + #Underline the text using the underline style in -underline type [switch]$Underline, - #Should Underline use single or double, normal or accounting mode : default is single normal + #Should Underline use single or double, normal or accounting mode : default is single normal [OfficeOpenXml.Style.ExcelUnderLineType]$UnderLineType = [OfficeOpenXml.Style.ExcelUnderLineType]::Single, #StrikeThrough text [switch]$StrikeThru, #Subscript or superscript [OfficeOpenXml.Style.ExcelVerticalAlignmentFont]$FontShift, #Font to use - Excel defaults to Calibri - [String]$FontName, + [String]$FontName, #Point size for the text [float]$FontSize, - #Change background colour + #Change background colour [System.Drawing.Color]$BackgroundColor, #Background pattern - solid by default [OfficeOpenXml.Style.ExcelFillStyle]$BackgroundPattern =[OfficeOpenXml.Style.ExcelFillStyle]::Solid , - #Secondary colour for background pattern - [Alias("PatternColour")] + #Secondary colour for background pattern + [Alias("PatternColour")] [System.Drawing.Color]$PatternColor, #Turn on text wrapping - [switch]$WrapText, - #Position cell contents to left, right or centre ... + [switch]$WrapText, + #Position cell contents to left, right or centre ... [OfficeOpenXml.Style.ExcelHorizontalAlignment]$HorizontalAlignment, - #Position cell contents to top bottom or centre + #Position cell contents to top bottom or centre [OfficeOpenXml.Style.ExcelVerticalAlignment]$VerticalAlignment, #Degrees to rotate text. Up to +90 for anti-clockwise ("upwards"), or to -90 for clockwise. [ValidateRange(-90,90)] [int]$TextRotation , #Autofit cells to width (columns or ranges only) - [switch]$AutoFit, + [switch]$AutoFit, #Set cells to a fixed width (columns or ranges only), ignored if Autofit is specified [float]$Width, #Set cells to a fixed hieght (rows or ranges only) - [float]$Height, + [float]$Height, #Hide a row or column (not a range) - [switch]$Hidden + [switch]$Hidden ) process { - Foreach ($range in $Address) { + Foreach ($range in $Address) { if ($ResetFont) {$Range.Style.Font.Color.SetColor("Black") $Range.Style.Font.Bold = $false $Range.Style.Font.Italic = $false $Range.Style.Font.UnderLine = $false - $Range.Style.Font.Strike = $falsee + $Range.Style.Font.Strike = $false } if ($Underline) {$Range.Style.Font.UnderLine = $true $Range.Style.Font.UnderLineType =$UnderLineType @@ -170,7 +170,7 @@ Function Set-Format { if ($StrikeThru) {$Range.Style.Font.Strike = $true } if ($FontShift) {$Range.Style.Font.VerticalAlign = $FontShift } if ($FontColor) {$Range.Style.Font.Color.SetColor( $FontColor ) } - if ($BorderRound) {$Range.Style.Border.BorderAround( $BorderAround ) } + if ($BorderAround) {$Range.Style.Border.BorderAround( $BorderAround ) } if ($NumberFormat) {$Range.Style.Numberformat.Format= $NumberFormat } if ($TextRotation) {$Range.Style.TextRotation = $TextRotation } if ($WrapText) {$Range.Style.WrapText = $true } @@ -179,7 +179,7 @@ Function Set-Format { if ($BackgroundColor) { $Range.Style.Fill.PatternType = $BackgroundPattern - $Range.Style.Fill.BackgroundColor.SetColor($BackgroundColor) + $Range.Style.Fill.BackgroundColor.SetColor($BackgroundColor) if ($PatternColor) { $range.Style.Fill.PatternColor.SetColor( $PatternColor) } @@ -191,13 +191,13 @@ Function Set-Format { ($range.Start.Row)..($range.Start.Row + $range.Rows) | ForEach-Object {$ws.Row($_).Height = $Height } } - else {Write-Warning -Message ("Can set the height of a row or a range but not a {0} object" -f ($Range.GetType().name)) } + else {Write-Warning -Message ("Can set the height of a row or a range but not a {0} object" -f ($Range.GetType().name)) } } if ($AutoFit) { if ($Range -is [OfficeOpenXml.ExcelColumn]) {$Range.AutoFit() } - elseif ($Range -is [OfficeOpenXml.ExcelRange] ) {$Range.AutoFitColumns() } - else {Write-Warning -Message ("Can autofit a column or a range but not a {0} object" -f ($Range.GetType().name)) } - + elseif ($Range -is [OfficeOpenXml.ExcelRange] ) {$Range.AutoFitColumns() } + else {Write-Warning -Message ("Can autofit a column or a range but not a {0} object" -f ($Range.GetType().name)) } + } elseif ($Width) { if ($Range -is [OfficeOpenXml.ExcelColumn]) {$Range.Width = $Width} @@ -205,7 +205,7 @@ Function Set-Format { ($range.Start.Column)..($range.Start.Column+ $range.Columns) | ForEach-Object {$ws.Column($_).Width = $Width} } - else {Write-Warning -Message ("Can set the width of a column or a range but not a {0} object" -f ($Range.GetType().name)) } + else {Write-Warning -Message ("Can set the width of a column or a range but not a {0} object" -f ($Range.GetType().name)) } } if ($Hidden) { if ($Range -is [OfficeOpenXml.ExcelRow] -or @@ -216,12 +216,12 @@ Function Set-Format { } } -#Argument completer for colours. If we have PS 5 or Tab expansion++ then we'll register it. Otherwise it does nothing. +#Argument completer for colours. If we have PS 5 or Tab expansion++ then we'll register it. Otherwise it does nothing. Function ColorCompletion{ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) [System.Drawing.KnownColor].GetFields() | Where-Object {$_.IsStatic -and $_.name -like "$wordToComplete*" } | Sort-Object name | ForEach-Object {New-CompletionResult $_.name $_.name - } + } } if (Get-Command -Name register-argumentCompleter -ErrorAction SilentlyContinue) { diff --git a/images/CustomReport.png b/images/CustomReport.png new file mode 100644 index 0000000..675f0fb Binary files /dev/null and b/images/CustomReport.png differ diff --git a/images/PivotTableFilter.png b/images/PivotTableFilter.png new file mode 100644 index 0000000..af012a7 Binary files /dev/null and b/images/PivotTableFilter.png differ