diff --git a/Examples/Tables/TotalsRow.ps1 b/Examples/Tables/TotalsRow.ps1 new file mode 100644 index 0000000..1580dae --- /dev/null +++ b/Examples/Tables/TotalsRow.ps1 @@ -0,0 +1,15 @@ +try {Import-Module $PSScriptRoot\..\..\ImportExcel.psd1} catch {throw ; return} + +$r = Get-ChildItem C:\WINDOWS\system32 -File + +$TotalSettings = @{ + Length = "Sum" + Name = "Count" + Extension = @{ + # You can create the formula in an Excel workbook first and copy-paste it here + # This syntax can only be used for the Custom type + Custom = "=COUNTIF([Extension];`".exe`")" + } +} + +$r | Export-Excel -TableName system32files -TableStyle Medium10 -TotalSettings $TotalSettings -Show \ No newline at end of file diff --git a/Public/Add-ExcelTable.ps1 b/Public/Add-ExcelTable.ps1 index 5cb25ec..5a179a8 100644 --- a/Public/Add-ExcelTable.ps1 +++ b/Public/Add-ExcelTable.ps1 @@ -55,6 +55,31 @@ function Add-ExcelTable { $tbl.ShowTotal = $true foreach ($k in $TotalSettings.keys) { if (-not $tbl.Columns[$k]) {Write-Warning -Message "Table does not have a Column '$k'."} + elseif ($TotalSettings[$k] -is [HashTable] -and $TotalSettings[$k].Keys.Count -eq 1 -and $TotalSettings[$k].Keys[0] -eq "Custom") { + $formula = $TotalSettings[$k][($TotalSettings[$k].Keys[0])] | Select -First 1 + ### A function in Excel uses ";" between parameters but the OpenXML parameter separator is "," + ### Only replace semicolon when it's NOT somewhere between quotes quotes. + # Get all text between quotes + $QuoteMatches = [Regex]::Matches($formula,"`"[^`"]*`"|'[^']*'") + # Create array with all indexes of characters between quotes (and the quotes themselves) + $QuoteCharIndexes = $( + Foreach ($QuoteMatch in $QuoteMatches) { + (($QuoteMatch.Index)..($QuoteMatch.Index + $QuoteMatch.Length - 1)) + } + ) + + # Get all semicolons + $SemiColonMatches = [Regex]::Matches($formula, ";") + # Replace the semicolons of which the index is not in the list of quote-text indexes + Foreach ($SemiColonMatch in $SemiColonMatches.Index) { + If ($QuoteCharIndexes -notcontains $SemiColonMatch) { + $formula = $formula.remove($SemiColonMatch,1).Insert($SemiColonMatch,",") + } + } + + # Configure the formula. The TotalsRowFunction is automatically set to "Custom" when the TotalsRowFormula is set. + $tbl.Columns[$k].TotalsRowFormula = $formula + } elseif ($TotalSettings[$k] -notin @("Average", "Count", "CountNums", "Max", "Min", "None", "StdDev", "Sum", "Var") ) { Write-Warning -Message "'$($TotalSettings[$k])' is not a valid total function." } diff --git a/__tests__/Export-Excel.Tests.ps1 b/__tests__/Export-Excel.Tests.ps1 index 7dc4582..e1c8be1 100644 --- a/__tests__/Export-Excel.Tests.ps1 +++ b/__tests__/Export-Excel.Tests.ps1 @@ -696,6 +696,9 @@ Describe ExportExcel -Tag "ExportExcel" { Id = "COUNT" WS = "SUM" Handles = "AVERAGE" + CPU = @{ + Custom = '=COUNTIF([CPU];"<1")' + } } $Processes | Export-Excel $path -TableName "processes" -TotalSettings $TotalSettings $TotalRows = $Processes.count + 2 # Column header + Data (50 processes) + Totals row @@ -708,22 +711,27 @@ Describe ExportExcel -Tag "ExportExcel" { $ws.tables[0].ShowTotal | Should -Be $True } - it "Added three calculations in the totals row".PadRight(87) { + it "Added four calculations in the totals row".PadRight(87) { $IDcolumn = $ws.Tables[0].Columns | Where-Object { $_.Name -eq "id" } $WScolumn = $ws.Tables[0].Columns | Where-Object { $_.Name -eq "WS" } $HandlesColumn = $ws.Tables[0].Columns | Where-Object { $_.Name -eq "Handles" } + $CPUColumn = $ws.Tables[0].Columns | Where-Object { $_.Name -eq "CPU" } $IDcolumn | Select-Object -ExpandProperty TotalsRowFunction | Should -Be "Count" $WScolumn | Select-Object -ExpandProperty TotalsRowFunction | Should -Be "Sum" $HandlesColumn | Select-Object -ExpandProperty TotalsRowFunction | Should -Be "Average" + $CPUColumn | Select-Object -ExpandProperty TotalsRowFunction | Should -Be "Custom" + $CPUColumn | Select-Object -ExpandProperty TotalsRowFormula | Should -Be 'COUNTIF([CPU],"<1")' $CountAddress = "{0}{1}" -f (Get-ExcelColumnName -ColumnNumber $IDcolumn.Id).ColumnName, $TotalRows $SumAddress = "{0}{1}" -f (Get-ExcelColumnName -ColumnNumber $WScolumn.Id).ColumnName, $TotalRows $AverageAddress = "{0}{1}" -f (Get-ExcelColumnName -ColumnNumber $HandlesColumn.Id).ColumnName, $TotalRows + $CustomAddress = "{0}{1}" -f (Get-ExcelColumnName -ColumnNumber $CPUColumn.Id).ColumnName, $TotalRows $ws.Cells[$CountAddress].Formula | Should -Be "SUBTOTAL(103,processes[Id])" $ws.Cells[$SumAddress].Formula | Should -Be "SUBTOTAL(109,processes[Ws])" $ws.Cells[$AverageAddress].Formula | Should -Be "SUBTOTAL(101,processes[Handles])" + $ws.Cells[$CustomAddress].Formula | Should -Be 'COUNTIF([CPU],"<1")' } AfterEach {