From 1768c0ac9255398e27e47c5bdf5f920bcc7e9cb7 Mon Sep 17 00:00:00 2001 From: Stahler Date: Fri, 10 Sep 2021 14:17:44 -0400 Subject: [PATCH 001/140] Update open-excelpackage.md --- mdhelp/en/open-excelpackage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mdhelp/en/open-excelpackage.md b/mdhelp/en/open-excelpackage.md index 86c1429..be6dc95 100644 --- a/mdhelp/en/open-excelpackage.md +++ b/mdhelp/en/open-excelpackage.md @@ -9,7 +9,7 @@ schema: 2.0.0 ## SYNOPSIS -Returns an ExcelPackage object for the specified XLSX fil.e +Returns an ExcelPackage object for the specified XLSX file. ## SYNTAX From ab5600c9ba1e576a90e693d9d7db23567a12bc42 Mon Sep 17 00:00:00 2001 From: Doug Finke Date: Fri, 10 Sep 2021 18:40:57 -0400 Subject: [PATCH 002/140] bump version --- ImportExcel.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index 2d4f540..df9676a 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.2.2' + ModuleVersion = '7.2.3' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' From 6c35d5b018a99f9a47c503907008561f47b7df29 Mon Sep 17 00:00:00 2001 From: Doug Finke Date: Fri, 10 Sep 2021 18:41:03 -0400 Subject: [PATCH 003/140] Updated --- changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.md b/changelog.md index 745c249..915b810 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,8 @@ +# v7.2.3 + +- Fix inline help, thank you [Wes Stahler](https://github.com/stahler) + + # v7.2.2 - Improved checks for Linux, Mac and PS 5.1 From 26827b0764a5ca47de6a2cc46736737d31dae5ef Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 14 Sep 2021 15:44:03 -0400 Subject: [PATCH 004/140] bump version --- ImportExcel.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index df9676a..8a267c3 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.2.3' + ModuleVersion = '7.3.0' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' From 50928e8e3b3f7be47a0ca7fa8cfe1378c130567f Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 14 Sep 2021 15:44:11 -0400 Subject: [PATCH 005/140] Update --- changelog.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 915b810..bf200b8 100644 --- a/changelog.md +++ b/changelog.md @@ -1,8 +1,11 @@ +# v7.3.0 + +- Fix throwing error when a Worksheet name collides with a method, or property name on the `OfficeOpenXml.ExcelPackage` package + # v7.2.3 - Fix inline help, thank you [Wes Stahler](https://github.com/stahler) - # v7.2.2 - Improved checks for Linux, Mac and PS 5.1 From 23a2ac394fcb27261b5a24f55828f44077c344e6 Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 14 Sep 2021 15:44:32 -0400 Subject: [PATCH 006/140] Add try/catch, warning, and tests --- Public/Open-ExcelPackage.ps1 | 27 +++++++++------- __tests__/Open-ExcelPackage.tests.ps1 | 39 +++++++++++++++++++++++ __tests__/UnsupportedWorkSheetNames.xlsx | Bin 0 -> 21137 bytes 3 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 __tests__/Open-ExcelPackage.tests.ps1 create mode 100644 __tests__/UnsupportedWorkSheetNames.xlsx diff --git a/Public/Open-ExcelPackage.ps1 b/Public/Open-ExcelPackage.ps1 index a645e07..7c0d077 100644 --- a/Public/Open-ExcelPackage.ps1 +++ b/Public/Open-ExcelPackage.ps1 @@ -1,10 +1,10 @@ -function Open-ExcelPackage { +function Open-ExcelPackage { [CmdLetBinding()] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword","")] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [OutputType([OfficeOpenXml.ExcelPackage])] param( #The path to the file to open. - [Parameter(Mandatory=$true)]$Path, + [Parameter(Mandatory = $true)]$Path, #If specified, any running instances of Excel will be terminated before opening the file. [switch]$KillExcel, #The password for a protected worksheet, as a [normal] string (not a secure string). @@ -13,7 +13,7 @@ [switch]$Create ) - if($KillExcel) { + if ($KillExcel) { Get-Process -Name "excel" -ErrorAction Ignore | Stop-Process while (Get-Process -Name "excel" -ErrorAction Ignore) {} } @@ -24,21 +24,26 @@ #Create the directory if required. $targetPath = Split-Path -Parent -Path $Path if (!(Test-Path -Path $targetPath)) { - Write-Debug "Base path $($targetPath) does not exist, creating" - $null = New-item -ItemType Directory -Path $targetPath -ErrorAction Ignore + Write-Debug "Base path $($targetPath) does not exist, creating" + $null = New-item -ItemType Directory -Path $targetPath -ErrorAction Ignore } New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path } elseif (Test-Path -Path $path) { - if ($Password) {$pkgobj = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path , $Password } - else {$pkgobj = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path } + if ($Password) { $pkgobj = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path , $Password } + else { $pkgobj = New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList $Path } if ($pkgobj) { foreach ($w in $pkgobj.Workbook.Worksheets) { $sb = [scriptblock]::Create(('$this.workbook.Worksheets["{0}"]' -f $w.name)) - Add-Member -InputObject $pkgobj -MemberType ScriptProperty -Name $w.name -Value $sb + try { + Add-Member -InputObject $pkgobj -MemberType ScriptProperty -Name $w.name -Value $sb -ErrorAction Stop + } + catch { + Write-Warning "Could not add sheet $($w.name) as 'short cut', you need to access it via `$wb.Worksheets['$($w.name)'] " + } } return $pkgobj } } - else {Write-Warning "Could not find $path" } - } + else { Write-Warning "Could not find $path" } +} diff --git a/__tests__/Open-ExcelPackage.tests.ps1 b/__tests__/Open-ExcelPackage.tests.ps1 new file mode 100644 index 0000000..1056bcb --- /dev/null +++ b/__tests__/Open-ExcelPackage.tests.ps1 @@ -0,0 +1,39 @@ +#Requires -Modules Pester + +if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) { + Import-Module $PSScriptRoot\..\ImportExcel.psd1 +} + +<# +Methods +------- +Dispose +Equals +GetAsByteArray +GetHashCode +GetType +Load +Save +SaveAs +ToString + +Properties +---------- + +Compatibility +Compression +DoAdjustDrawings +Encryption +File +Package +Stream +Workbook +#> + +Describe "Test Open Excel Package" -Tag Open-ExcelPackage { + It "Should handle opening a workbook with Worksheet Names that will cause errors" { + $xlFilename = "$PSScriptRoot\UnsupportedWorkSheetNames.xlsx" + + { Open-ExcelPackage -Path $xlFilename -ErrorAction Stop } | Should -Not -Throw + } +} \ No newline at end of file diff --git a/__tests__/UnsupportedWorkSheetNames.xlsx b/__tests__/UnsupportedWorkSheetNames.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b27620b1396804566798d9937c5c536ce50290e9 GIT binary patch literal 21137 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 literal 0 HcmV?d00001 From 533ed07ac887b65848c118cf6113ac83e79a801e Mon Sep 17 00:00:00 2001 From: Doug Finke Date: Fri, 17 Sep 2021 08:07:56 -0400 Subject: [PATCH 007/140] Remove lowercase public used for GitBook, no longer needed. #1082 --- public/README.md | 2 - public/convertfrom-exceldata.md | 157 --------- public/convertto-excelxlsx.md | 71 ---- public/get-excelcolumnname.md | 59 ---- public/get-htmltable.md | 116 ------- public/get-range.md | 83 ----- public/get-xyrange.md | 55 --- public/import-html.md | 116 ------- public/import-ups.md | 69 ---- public/import-usps.md | 69 ---- public/invoke-sum.md | 83 ----- public/new-excelstyle.md | 535 ------------------------------ public/new-plot.md | 41 --- public/new-psitem.md | 41 --- public/set-cellstyle.md | 113 ------- public/set-worksheetprotection.md | 329 ------------------ 16 files changed, 1939 deletions(-) delete mode 100644 public/README.md delete mode 100644 public/convertfrom-exceldata.md delete mode 100644 public/convertto-excelxlsx.md delete mode 100644 public/get-excelcolumnname.md delete mode 100644 public/get-htmltable.md delete mode 100644 public/get-range.md delete mode 100644 public/get-xyrange.md delete mode 100644 public/import-html.md delete mode 100644 public/import-ups.md delete mode 100644 public/import-usps.md delete mode 100644 public/invoke-sum.md delete mode 100644 public/new-excelstyle.md delete mode 100644 public/new-plot.md delete mode 100644 public/new-psitem.md delete mode 100644 public/set-cellstyle.md delete mode 100644 public/set-worksheetprotection.md diff --git a/public/README.md b/public/README.md deleted file mode 100644 index 557839f..0000000 --- a/public/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Public - diff --git a/public/convertfrom-exceldata.md b/public/convertfrom-exceldata.md deleted file mode 100644 index b85ef3e..0000000 --- a/public/convertfrom-exceldata.md +++ /dev/null @@ -1,157 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: null -schema: 2.0.0 ---- - -# ConvertFrom-ExcelData - -## SYNOPSIS - -Reads data from a sheet, and for each row, calls a custom scriptblock with a list of property names and the row of data. - -## SYNTAX - -```text -ConvertFrom-ExcelData [-Path] [[-ScriptBlock] ] [[-WorksheetName] ] - [[-HeaderRow] ] [[-Header] ] [-NoHeader] [-DataOnly] [] -``` - -## DESCRIPTION - -## EXAMPLES - -### EXAMPLE 1 - -```text -ConvertFrom-ExcelData .\testSQLGen.xlsx { -``` - -param\($propertyNames, $record\) - -```text -$reportRecord = @() -foreach ($pn in $propertyNames) { - $reportRecord += "{0}: {1}" -f $pn, $record.$pn -} -$reportRecord +="" -$reportRecord -join "\`r\`n" -``` - -} - -First: John Last: Doe The Zip: 12345 .... - -## PARAMETERS - -### -Path - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: FullName - -Required: True -Position: 1 -Default value: None -Accept pipeline input: True (ByPropertyName, ByValue) -Accept wildcard characters: False -``` - -### -ScriptBlock - -```yaml -Type: ScriptBlock -Parameter Sets: (All) -Aliases: - -Required: False -Position: 2 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -WorksheetName - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: Sheet - -Required: False -Position: 3 -Default value: 1 -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -HeaderRow - -```yaml -Type: Int32 -Parameter Sets: (All) -Aliases: - -Required: False -Position: 4 -Default value: 1 -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Header - -```yaml -Type: String[] -Parameter Sets: (All) -Aliases: - -Required: False -Position: 5 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -NoHeader - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: False -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -DataOnly - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: False -Accept pipeline input: False -Accept wildcard characters: False -``` - -### CommonParameters - -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about\_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). - -## INPUTS - -## OUTPUTS - -## NOTES - -## RELATED LINKS - diff --git a/public/convertto-excelxlsx.md b/public/convertto-excelxlsx.md deleted file mode 100644 index f7c1571..0000000 --- a/public/convertto-excelxlsx.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: null -schema: 2.0.0 ---- - -# ConvertTo-ExcelXlsx - -## SYNOPSIS - -Converts an Excel xls to a xlsx using -ComObject - -## SYNTAX - -```text -ConvertTo-ExcelXlsx [-Path] [-Force] [] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -Path - -```yaml -Type: String -Parameter Sets: (All) -Aliases: - -Required: True -Position: 1 -Default value: None -Accept pipeline input: True (ByValue) -Accept wildcard characters: False -``` - -### -Force - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: False -Accept pipeline input: False -Accept wildcard characters: False -``` - -### CommonParameters - -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about\_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). - -## INPUTS - -## OUTPUTS - -## NOTES - -## RELATED LINKS - diff --git a/public/get-excelcolumnname.md b/public/get-excelcolumnname.md deleted file mode 100644 index 352ef39..0000000 --- a/public/get-excelcolumnname.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: 'https://github.com/dfinke/ImportExcel' -schema: 2.0.0 ---- - -# Get-ExcelColumnName - -## SYNOPSIS - -## SYNTAX - -```text -Get-ExcelColumnName [[-ColumnNumber] ] [] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -ColumnNumber - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 0 -Default value: None -Accept pipeline input: True (ByValue) -Accept wildcard characters: False -``` - -### CommonParameters - -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about\_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). - -## INPUTS - -### System.Object - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/get-htmltable.md b/public/get-htmltable.md deleted file mode 100644 index d27e1e6..0000000 --- a/public/get-htmltable.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: 'https://github.com/dfinke/ImportExcel' -schema: 2.0.0 ---- - -# Get-HtmlTable - -## SYNOPSIS - -## SYNTAX - -```text -Get-HtmlTable [-Url] [[-TableIndex] ] [[-Header] ] [[-FirstDataRow] ] - [-UseDefaultCredentials] [] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -FirstDataRow - -```yaml -Type: Int32 -Parameter Sets: (All) -Aliases: - -Required: False -Position: 3 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Header - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 2 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -UseDefaultCredentials - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -TableIndex - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Url - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: True -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### CommonParameters - -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about\_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/get-range.md b/public/get-range.md deleted file mode 100644 index 94b3dbc..0000000 --- a/public/get-range.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: 'https://github.com/dfinke/ImportExcel' -schema: 2.0.0 ---- - -# Get-Range - -## SYNOPSIS - -## SYNTAX - -```text -Get-Range [[-Start] ] [[-Stop] ] [[-Step] ] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -start - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Step - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 2 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -stop - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/get-xyrange.md b/public/get-xyrange.md deleted file mode 100644 index 242e5d2..0000000 --- a/public/get-xyrange.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: 'https://github.com/dfinke/ImportExcel' -schema: 2.0.0 ---- - -# Get-XYRange - -## SYNOPSIS - -## SYNTAX - -```text -Get-XYRange [[-TargetData] ] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -TargetData - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/import-html.md b/public/import-html.md deleted file mode 100644 index 94d5c18..0000000 --- a/public/import-html.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: 'https://github.com/dfinke/ImportExcel' -schema: 2.0.0 ---- - -# Import-Html - -## SYNOPSIS - -## SYNTAX - -```text -Import-Html [[-Url] ] [[-Index] ] [[-Header] ] [[-FirstDataRow] ] - [-UseDefaultCredentials] [] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -FirstDataRow - -```yaml -Type: Int32 -Parameter Sets: (All) -Aliases: - -Required: False -Position: 3 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Header - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 2 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -UseDefaultCredentials - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Index - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Url - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### CommonParameters - -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about\_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/import-ups.md b/public/import-ups.md deleted file mode 100644 index 3b14f99..0000000 --- a/public/import-ups.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: 'https://github.com/dfinke/ImportExcel' -schema: 2.0.0 ---- - -# Import-UPS - -## SYNOPSIS - -## SYNTAX - -```text -Import-UPS [[-TrackingNumber] ] [-UseDefaultCredentials] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -TrackingNumber - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -UseDefaultCredentials - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/import-usps.md b/public/import-usps.md deleted file mode 100644 index e5e033e..0000000 --- a/public/import-usps.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: 'https://github.com/dfinke/ImportExcel' -schema: 2.0.0 ---- - -# Import-USPS - -## SYNOPSIS - -## SYNTAX - -```text -Import-USPS [[-TrackingNumber] ] [-UseDefaultCredentials] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -TrackingNumber - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -UseDefaultCredentials - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/invoke-sum.md b/public/invoke-sum.md deleted file mode 100644 index 040916d..0000000 --- a/public/invoke-sum.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: 'https://github.com/dfinke/ImportExcel' -schema: 2.0.0 ---- - -# Invoke-Sum - -## SYNOPSIS - -## SYNTAX - -```text -Invoke-Sum [[-Data] ] [[-Dimension] ] [[-Measure] ] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -Data - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Dimension - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Measure - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 2 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/new-excelstyle.md b/public/new-excelstyle.md deleted file mode 100644 index 17272ae..0000000 --- a/public/new-excelstyle.md +++ /dev/null @@ -1,535 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: null -schema: 2.0.0 ---- - -# New-ExcelStyle - -## SYNOPSIS - -## SYNTAX - -```text -New-ExcelStyle [[-Range] ] [[-NumberFormat] ] [[-BorderAround] ] - [[-BorderColor] ] [[-BorderBottom] ] [[-BorderTop] ] - [[-BorderLeft] ] [[-BorderRight] ] [[-FontColor] ] - [[-Value] ] [[-Formula] ] [-ArrayFormula] [-ResetFont] [-Bold] [-Italic] [-Underline] - [[-UnderLineType] ] [-StrikeThru] [[-FontShift] ] - [[-FontName] ] [[-FontSize] ] [[-BackgroundColor] ] - [[-BackgroundPattern] ] [[-PatternColor] ] [-WrapText] - [[-HorizontalAlignment] ] [[-VerticalAlignment] ] - [[-TextRotation] ] [-AutoSize] [[-Width] ] [[-Height] ] [-Hidden] [-Locked] [-Merge] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -ArrayFormula - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AutoSize - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: AutoFit - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BackgroundColor - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 15 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BackgroundPattern - -```yaml -Type: ExcelFillStyle -Parameter Sets: (All) -Aliases: -Accepted values: None, Solid, DarkGray, MediumGray, LightGray, Gray125, Gray0625, DarkVertical, DarkHorizontal, DarkDown, DarkUp, DarkGrid, DarkTrellis, LightVertical, LightHorizontal, LightDown, LightUp, LightGrid, LightTrellis - -Required: False -Position: 16 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Bold - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BorderAround - -```yaml -Type: ExcelBorderStyle -Parameter Sets: (All) -Aliases: -Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double - -Required: False -Position: 2 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BorderBottom - -```yaml -Type: ExcelBorderStyle -Parameter Sets: (All) -Aliases: -Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double - -Required: False -Position: 4 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BorderColor - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 3 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BorderLeft - -```yaml -Type: ExcelBorderStyle -Parameter Sets: (All) -Aliases: -Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double - -Required: False -Position: 6 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BorderRight - -```yaml -Type: ExcelBorderStyle -Parameter Sets: (All) -Aliases: -Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double - -Required: False -Position: 7 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BorderTop - -```yaml -Type: ExcelBorderStyle -Parameter Sets: (All) -Aliases: -Accepted values: None, Hair, Dotted, DashDot, Thin, DashDotDot, Dashed, MediumDashDotDot, MediumDashed, MediumDashDot, Thick, Medium, Double - -Required: False -Position: 5 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -FontColor - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: ForegroundColor - -Required: False -Position: 8 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -FontName - -```yaml -Type: String -Parameter Sets: (All) -Aliases: - -Required: False -Position: 13 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -FontShift - -```yaml -Type: ExcelVerticalAlignmentFont -Parameter Sets: (All) -Aliases: -Accepted values: None, Baseline, Subscript, Superscript - -Required: False -Position: 12 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -FontSize - -```yaml -Type: Single -Parameter Sets: (All) -Aliases: - -Required: False -Position: 14 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Formula - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 10 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Height - -```yaml -Type: Single -Parameter Sets: (All) -Aliases: - -Required: False -Position: 22 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Hidden - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -HorizontalAlignment - -```yaml -Type: ExcelHorizontalAlignment -Parameter Sets: (All) -Aliases: -Accepted values: General, Left, Center, CenterContinuous, Right, Fill, Distributed, Justify - -Required: False -Position: 18 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Italic - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Locked - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Merge - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -NumberFormat - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: NFormat - -Required: False -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -PatternColor - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: PatternColour - -Required: False -Position: 17 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Range - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: Address - -Required: False -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -ResetFont - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -StrikeThru - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -TextRotation - -```yaml -Type: Int32 -Parameter Sets: (All) -Aliases: - -Required: False -Position: 20 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -UnderLineType - -```yaml -Type: ExcelUnderLineType -Parameter Sets: (All) -Aliases: -Accepted values: None, Single, Double, SingleAccounting, DoubleAccounting - -Required: False -Position: 11 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Underline - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Value - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 9 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -VerticalAlignment - -```yaml -Type: ExcelVerticalAlignment -Parameter Sets: (All) -Aliases: -Accepted values: Top, Center, Bottom, Distributed, Justify - -Required: False -Position: 19 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Width - -```yaml -Type: Single -Parameter Sets: (All) -Aliases: - -Required: False -Position: 21 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -WrapText - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/new-plot.md b/public/new-plot.md deleted file mode 100644 index 0796339..0000000 --- a/public/new-plot.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: null -schema: 2.0.0 ---- - -# New-Plot - -## SYNOPSIS - -## SYNTAX - -```text -New-Plot -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/new-psitem.md b/public/new-psitem.md deleted file mode 100644 index 88a461f..0000000 --- a/public/new-psitem.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: null -schema: 2.0.0 ---- - -# New-PSItem - -## SYNOPSIS - -## SYNTAX - -```text -New-PSItem -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/set-cellstyle.md b/public/set-cellstyle.md deleted file mode 100644 index e4fbb50..0000000 --- a/public/set-cellstyle.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: null -schema: 2.0.0 ---- - -# Set-CellStyle - -## SYNOPSIS - -## SYNTAX - -```text -Set-CellStyle [[-Worksheet] ] [[-Row] ] [[-LastColumn] ] [[-Pattern] ] - [[-Color] ] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -Color - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 4 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -LastColumn - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 2 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Pattern - -```yaml -Type: ExcelFillStyle -Parameter Sets: (All) -Aliases: -Accepted values: None, Solid, DarkGray, MediumGray, LightGray, Gray125, Gray0625, DarkVertical, DarkHorizontal, DarkDown, DarkUp, DarkGrid, DarkTrellis, LightVertical, LightHorizontal, LightDown, LightUp, LightGrid, LightTrellis - -Required: False -Position: 3 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Row - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Worksheet - -```yaml -Type: Object -Parameter Sets: (All) -Aliases: - -Required: False -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - diff --git a/public/set-worksheetprotection.md b/public/set-worksheetprotection.md deleted file mode 100644 index f8340f3..0000000 --- a/public/set-worksheetprotection.md +++ /dev/null @@ -1,329 +0,0 @@ ---- -external help file: ImportExcel-help.xml -Module Name: ImportExcel -online version: null -schema: 2.0.0 ---- - -# Set-WorksheetProtection - -## SYNOPSIS - -## SYNTAX - -```text -Set-WorksheetProtection [-Worksheet] [-IsProtected] [-AllowAll] [-BlockSelectLockedCells] - [-BlockSelectUnlockedCells] [-AllowFormatCells] [-AllowFormatColumns] [-AllowFormatRows] [-AllowInsertColumns] - [-AllowInsertRows] [-AllowInsertHyperlinks] [-AllowDeleteColumns] [-AllowDeleteRows] [-AllowSort] - [-AllowAutoFilter] [-AllowPivotTables] [-BlockEditObject] [-BlockEditScenarios] [[-LockAddress] ] - [[-UnLockAddress] ] [] -``` - -## DESCRIPTION - -## EXAMPLES - -### Example 1 - -```text -PS C:\> {{ Add example code here }} -``` - -## PARAMETERS - -### -AllowAll - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowAutoFilter - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowDeleteColumns - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowDeleteRows - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowFormatCells - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowFormatColumns - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowFormatRows - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowInsertColumns - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowInsertHyperlinks - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowInsertRows - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowPivotTables - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -AllowSort - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BlockEditObject - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BlockEditScenarios - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BlockSelectLockedCells - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -BlockSelectUnlockedCells - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -IsProtected - -```yaml -Type: SwitchParameter -Parameter Sets: (All) -Aliases: - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -LockAddress - -```yaml -Type: String -Parameter Sets: (All) -Aliases: - -Required: False -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -UnLockAddress - -```yaml -Type: String -Parameter Sets: (All) -Aliases: - -Required: False -Position: 2 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Worksheet - -```yaml -Type: ExcelWorksheet -Parameter Sets: (All) -Aliases: - -Required: True -Position: 0 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### CommonParameters - -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about\_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). - -## INPUTS - -### None - -## OUTPUTS - -### System.Object - -## NOTES - -## RELATED LINKS - From a942f2133dfc0ee480e5dcd8208311a3a4dce37d Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Fri, 29 Oct 2021 13:21:52 -0400 Subject: [PATCH 008/140] Add basic function, tests, and sample file --- Public/Read-OleDbData.TestA.sql | 4 ++ Public/Read-OleDbData.TestB.sql | 7 ++ Public/Read-OleDbData.TestC.sql | 4 ++ Public/Read-OleDbData.TestD.sql | 10 +++ Public/Read-OleDbData.TestE.sql | 31 +++++++++ Public/Read-OleDbData.Tests.ps1 | 113 ++++++++++++++++++++++++++++++++ Public/Read-OleDbData.ps1 | 68 +++++++++++++++++++ Public/Read-OleDbData.xlsx | Bin 0 -> 16588 bytes 8 files changed, 237 insertions(+) create mode 100644 Public/Read-OleDbData.TestA.sql create mode 100644 Public/Read-OleDbData.TestB.sql create mode 100644 Public/Read-OleDbData.TestC.sql create mode 100644 Public/Read-OleDbData.TestD.sql create mode 100644 Public/Read-OleDbData.TestE.sql create mode 100644 Public/Read-OleDbData.Tests.ps1 create mode 100644 Public/Read-OleDbData.ps1 create mode 100644 Public/Read-OleDbData.xlsx diff --git a/Public/Read-OleDbData.TestA.sql b/Public/Read-OleDbData.TestA.sql new file mode 100644 index 0000000..576c6af --- /dev/null +++ b/Public/Read-OleDbData.TestA.sql @@ -0,0 +1,4 @@ +select + ROUND(F1) as [A1] +from + [sheet3$A1:A1] \ No newline at end of file diff --git a/Public/Read-OleDbData.TestB.sql b/Public/Read-OleDbData.TestB.sql new file mode 100644 index 0000000..9334b90 --- /dev/null +++ b/Public/Read-OleDbData.TestB.sql @@ -0,0 +1,7 @@ +select ROUND(F1) as [A1] from [sheet1$A1:A1] +union all select ROUND(F1) as [A1] from [sheet2$A1:A1] +union all select ROUND(F1) as [A1] from [sheet3$A1:A1] +union all select ROUND(F1) as [A1] from [sheet4$A1:A1] +union all select ROUND(F1) as [A1] from [sheet5$A1:A1] +union all select ROUND(F1) as [A1] from [sheet6$A1:A1] +union all select ROUND(F1) as [A1] from [sheet7$A1:A1] \ No newline at end of file diff --git a/Public/Read-OleDbData.TestC.sql b/Public/Read-OleDbData.TestC.sql new file mode 100644 index 0000000..9e3f5f7 --- /dev/null +++ b/Public/Read-OleDbData.TestC.sql @@ -0,0 +1,4 @@ +select + * +from + [sheet1$A1:E10] diff --git a/Public/Read-OleDbData.TestD.sql b/Public/Read-OleDbData.TestD.sql new file mode 100644 index 0000000..efb169c --- /dev/null +++ b/Public/Read-OleDbData.TestD.sql @@ -0,0 +1,10 @@ +select top 1 + 'All A1s' as [A1], + F1 as [Sheet1], + (select F1 FROM [sheet2$a1:a1]) as [Sheet2], + (select F1 FROM [sheet3$a1:a1]) as [Sheet3], + (select F1 FROM [sheet4$a1:a1]) as [Sheet4], + (select F1 FROM [sheet5$a1:a1]) as [Sheet5], + (select F1 FROM [sheet6$a1:a1]) as [Sheet6], + (select F1 FROM [sheet7$a1:a1]) as [Sheet7] +FROM [sheet1$a1:a1] \ No newline at end of file diff --git a/Public/Read-OleDbData.TestE.sql b/Public/Read-OleDbData.TestE.sql new file mode 100644 index 0000000..bd98cfa --- /dev/null +++ b/Public/Read-OleDbData.TestE.sql @@ -0,0 +1,31 @@ +select top 1 + 'All A1s Start from Sheet1' as [A1], + F1 as [Sheet1], + (select F1 FROM [sheet2$a1:a1]) as [Sheet2], + (select F1 FROM [sheet3$a1:a1]) as [Sheet3], + (select F1 FROM [sheet4$a1:a1]) as [Sheet4] +FROM [sheet1$a1:a1] +UNION ALL +select top 1 + 'All A1s Start from Sheet2' as [A1], + (select F1 FROM [sheet1$a1:a1]) as [Sheet1], + F1 as [Sheet2], + (select F1 FROM [sheet3$a1:a1]) as [Sheet3], + (select F1 FROM [sheet4$a1:a1]) as [Sheet4] +FROM [sheet2$a1:a1] +UNION ALL +select top 1 + 'All A1s Start from Sheet3' as [A1], + (select F1 FROM [sheet1$a1:a1]) as [Sheet1], + (select F1 FROM [sheet2$a1:a1]) as [Sheet2], + F1 as [Sheet3], + (select F1 FROM [sheet4$a1:a1]) as [Sheet4] +FROM [sheet3$a1:a1] +UNION ALL +select top 1 + 'All A1s Start from Sheet4' as [A1], + (select F1 FROM [sheet1$a1:a1]) as [Sheet1], + (select F1 FROM [sheet2$a1:a1]) as [Sheet2], + (select F1 FROM [sheet3$a1:a1]) as [Sheet3], + F1 as [Sheet4] +FROM [sheet4$a1:a1] diff --git a/Public/Read-OleDbData.Tests.ps1 b/Public/Read-OleDbData.Tests.ps1 new file mode 100644 index 0000000..c2cf65b --- /dev/null +++ b/Public/Read-OleDbData.Tests.ps1 @@ -0,0 +1,113 @@ +. .\Read-OleDbData.ps1 +Describe "Read-OleDbData" { + BeforeAll{ + $tfp = (Get-ChildItem Read-OleDbData.xlsx).fullname # test file path + $cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" + } + Context "When Read-OleDbData.xlsx and we want sheet1 a1" { + BeforeAll{ + $sql = "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + } + It "should be PSCustomObject" { + $Results.GetType().Name | Should -Be 'PSCustomObject' + } + It "should have length of 1" { + @($Results).length | Should -Be 1 + } + It "should be value of 1" { + $Results.A1 | Should -Be 1 + } + } + Context "When Read-OleDbData.xlsx and we want sheet2 a1" { + BeforeAll{ + $sql = "select ROUND(F1) as [A1] from [sheet2`$A1:A1]" + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + } + It "should be PSCustomObject" { + $Results.GetType().Name | Should -Be 'PSCustomObject' + } + It "should have length of 1" { + @($Results).length | Should -Be 1 + } + It "should be value of 2" { + $Results.A1 | Should -Be 2 + } + } + Context "When Read-OleDbData.xlsx and we want a1 on sheet3 and sql is in a file" { + BeforeAll{ + $sql = Get-Content .\Read-OleDbData.TestA.sql -raw + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + } + It "should be PSCustomObject" { + $Results.GetType().Name | Should -Be 'PSCustomObject' + } + It "should have length of 1" { + @($Results).length | Should -Be 1 + } + It "should be value of 2" { + $Results.A1 | Should -Be 3 + } + } + Context "When Read-OleDbData.xlsx, we want a1 on sheets1-7, want to validate the values match properly, and sql is in a file" { + BeforeAll{ + $sql = Get-Content .\Read-OleDbData.TestB.sql -raw + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + } + It "should be PSCustomObject" { + $Results[0].GetType().Name | Should -Be 'PSCustomObject' + } + It "should have length of 7" { + @($Results).length | Should -Be 7 + } + It "should have data where sum of all initial records match the value of the last record" { + $a = $Results.A1 + ($a[0..5] | Measure-Object -sum).sum | Should -Be $a[6] + } + } + Context "When Read-OleDbData.xlsx, select range sheet1 A1:E10, and sql is in a file" { + #note, this spreadsheet doesn't have the fields populated other than A1, so it will, correctly, return only one value + BeforeAll{ + $sql = Get-Content .\Read-OleDbData.TestC.sql -raw + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + } + It "should be PSCustomObject" { + $Results.GetType().Name | Should -Be 'PSCustomObject' + } + It "should have length of 1" { + @($Results).length | Should -Be 1 + } + } + Context "When Read-OleDbData.xlsx, select a1 from all sheets as a single record, and sql is in a file" { + #note, this spreadsheet doesn't have the fields populated other than A1, so it will, correctly, return only one value + BeforeAll{ + $sql = Get-Content .\Read-OleDbData.TestD.sql -raw + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + } + It "should be PSCustomObject" { + $Results.GetType().Name | Should -Be 'PSCustomObject' + } + It "should have length of 1" { + @($Results).length | Should -Be 1 + } + It "should have 8 properties" { + @($Results.psobject.Properties).length | Should -Be 8 + } + } + Context "When Read-OleDbData.xlsx, select a1 from all sheets as a single record multiple times to create a range, and sql is in a file" { + #note, this spreadsheet doesn't have the fields populated other than A1, so it will, correctly, return only one value + BeforeAll{ + $sql = Get-Content .\Read-OleDbData.TestE.sql -raw + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + } + It "should be Object[]" { + $Results.GetType().Name | Should -Be 'Object[]' + } + It "should have length of 4" { + @($Results).length | Should -Be 4 + } + It "should have 5 properties on first record" { + @($Results[0].psobject.Properties).length | Should -Be 5 + } + } +} diff --git a/Public/Read-OleDbData.ps1 b/Public/Read-OleDbData.ps1 new file mode 100644 index 0000000..579d904 --- /dev/null +++ b/Public/Read-OleDbData.ps1 @@ -0,0 +1,68 @@ +#Requires -Version 5 +function Read-OleDbData { + <# + .SYNOPSIS + Read data from an OleDb source using dotnet classes. This allows for OleDb queries against excel spreadsheets. Examples will only be for querying xlsx files. + + For additional documentation, see Microsoft's documentation on the System.Data OleDb namespace here: + https://docs.microsoft.com/en-us/dotnet/api/system.data.oledb + + .DESCRIPTION + Read data from an OleDb source using dotnet classes. This allows for OleDb queries against excel spreadsheets. Examples will only be for querying xlsx files using ACE. + + .EXAMPLE + Read-OleDbData ` + -ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=file.xlsx;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" ` + -SqlStatement "select ROUND(F1) as [A] from [sheet1$A1:A1]" + + .EXAMPLE + $ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=file.xlsx;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" + $SqlStatement = "select ROUND(F1) as [A] from [sheet1$A1:A1]" + Read-OleDbData -ConnectionString $ConnectionString -SqlStatement $SqlStatement + + .EXAMPLE + $ReadDataArgs = @{ + SqlStatement = Get-Content query.sql -Raw + ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=file.xlsx;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" + } + $Results = Read-OleDbData @ReadDataArgs + + #> + param( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [String] $ConnectionString, + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [String] $SqlStatement + ) + + if ($IsLinux -or $IsMacOS) { + #todo: possibly add support for linux/mac somehow. i haven't researched this at all as i + # don't have a need for that and i'm not sure anyone else would in this context, but it does + # appear that once upon a time mono had support for oledb, so maybe it is (or was) supported. + # mono link here: https://www.mono-project.com/archived/ole_db/ + Write-Error "Read-OleDbData only runs on Windows" + return + } + + #todo: add checks for dotnet libs + #todo: possibly add checks for ace drivers, but maybe only needed if we want to restrict usage. + # i currently just pass through the query and connection string so user is only limited by + # their own machine setup, but they have to check for those dependencies themselves. + #todo: possibly try/catch. i personally do not do this, as i let them throw naturally and catch + # them/handle them outside of this function. + #todo: possibly allow for DataSets instead of just DataTable. I used to use a similar method before + # switching to the sqlcmd module and use datasets as I had multiple tables coming back from + # sql sometimes. i think in this case, it's best to just keep it simple, but maybe someone + # out there would prefer to be able to get multiple tables back. i have not tested that + # with the OleDbDataAdapter. + #todo: possibly just return the datatable, i do it as below because i prefer to simplify the output + # and get rid of the extra fields that come back with the datatable or rows. + + $DataTable = new-object System.Data.DataTable + $DataAdapter = new-object System.Data.OleDb.OleDbDataAdapter $SqlStatement,$ConnectionString + $null = $DataAdapter.Fill($DataTable) + $null = $DataAdapter.Dispose() + $DataTable.Rows | Select-Object $DataTable.Columns.ColumnName +} \ No newline at end of file diff --git a/Public/Read-OleDbData.xlsx b/Public/Read-OleDbData.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5458ccfb403ef5417928af40c4dff8fe476cbc0c GIT binary patch literal 16588 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 Date: Fri, 29 Oct 2021 16:58:16 -0400 Subject: [PATCH 009/140] move tests into test folder --- {Public => __tests__}/Read-OleDbData.TestA.sql | 0 {Public => __tests__}/Read-OleDbData.TestB.sql | 0 {Public => __tests__}/Read-OleDbData.TestC.sql | 0 {Public => __tests__}/Read-OleDbData.TestD.sql | 0 {Public => __tests__}/Read-OleDbData.TestE.sql | 0 {Public => __tests__}/Read-OleDbData.Tests.ps1 | 1 - {Public => __tests__}/Read-OleDbData.xlsx | Bin 7 files changed, 1 deletion(-) rename {Public => __tests__}/Read-OleDbData.TestA.sql (100%) rename {Public => __tests__}/Read-OleDbData.TestB.sql (100%) rename {Public => __tests__}/Read-OleDbData.TestC.sql (100%) rename {Public => __tests__}/Read-OleDbData.TestD.sql (100%) rename {Public => __tests__}/Read-OleDbData.TestE.sql (100%) rename {Public => __tests__}/Read-OleDbData.Tests.ps1 (99%) rename {Public => __tests__}/Read-OleDbData.xlsx (100%) diff --git a/Public/Read-OleDbData.TestA.sql b/__tests__/Read-OleDbData.TestA.sql similarity index 100% rename from Public/Read-OleDbData.TestA.sql rename to __tests__/Read-OleDbData.TestA.sql diff --git a/Public/Read-OleDbData.TestB.sql b/__tests__/Read-OleDbData.TestB.sql similarity index 100% rename from Public/Read-OleDbData.TestB.sql rename to __tests__/Read-OleDbData.TestB.sql diff --git a/Public/Read-OleDbData.TestC.sql b/__tests__/Read-OleDbData.TestC.sql similarity index 100% rename from Public/Read-OleDbData.TestC.sql rename to __tests__/Read-OleDbData.TestC.sql diff --git a/Public/Read-OleDbData.TestD.sql b/__tests__/Read-OleDbData.TestD.sql similarity index 100% rename from Public/Read-OleDbData.TestD.sql rename to __tests__/Read-OleDbData.TestD.sql diff --git a/Public/Read-OleDbData.TestE.sql b/__tests__/Read-OleDbData.TestE.sql similarity index 100% rename from Public/Read-OleDbData.TestE.sql rename to __tests__/Read-OleDbData.TestE.sql diff --git a/Public/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbData.Tests.ps1 similarity index 99% rename from Public/Read-OleDbData.Tests.ps1 rename to __tests__/Read-OleDbData.Tests.ps1 index c2cf65b..c0b10bc 100644 --- a/Public/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbData.Tests.ps1 @@ -1,4 +1,3 @@ -. .\Read-OleDbData.ps1 Describe "Read-OleDbData" { BeforeAll{ $tfp = (Get-ChildItem Read-OleDbData.xlsx).fullname # test file path diff --git a/Public/Read-OleDbData.xlsx b/__tests__/Read-OleDbData.xlsx similarity index 100% rename from Public/Read-OleDbData.xlsx rename to __tests__/Read-OleDbData.xlsx From e8c3d96f43c89a1c8f8a618eb010cc432cb0e7b4 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Fri, 29 Oct 2021 21:58:05 -0400 Subject: [PATCH 010/140] Tests relocated and updated. All passing. --- .../Read-OleDbData.TestA.sql | 0 .../Read-OleDbData.TestB.sql | 0 .../Read-OleDbData.TestC.sql | 0 .../Read-OleDbData.TestD.sql | 0 .../Read-OleDbData.TestE.sql | 0 .../Read-OleDbData.Tests.ps1 | 42 ++++++++---------- .../Read-OleDbData.xlsx | Bin 7 files changed, 19 insertions(+), 23 deletions(-) rename __tests__/{ => Read-OleDbDataTests}/Read-OleDbData.TestA.sql (100%) rename __tests__/{ => Read-OleDbDataTests}/Read-OleDbData.TestB.sql (100%) rename __tests__/{ => Read-OleDbDataTests}/Read-OleDbData.TestC.sql (100%) rename __tests__/{ => Read-OleDbDataTests}/Read-OleDbData.TestD.sql (100%) rename __tests__/{ => Read-OleDbDataTests}/Read-OleDbData.TestE.sql (100%) rename __tests__/{ => Read-OleDbDataTests}/Read-OleDbData.Tests.ps1 (81%) rename __tests__/{ => Read-OleDbDataTests}/Read-OleDbData.xlsx (100%) diff --git a/__tests__/Read-OleDbData.TestA.sql b/__tests__/Read-OleDbDataTests/Read-OleDbData.TestA.sql similarity index 100% rename from __tests__/Read-OleDbData.TestA.sql rename to __tests__/Read-OleDbDataTests/Read-OleDbData.TestA.sql diff --git a/__tests__/Read-OleDbData.TestB.sql b/__tests__/Read-OleDbDataTests/Read-OleDbData.TestB.sql similarity index 100% rename from __tests__/Read-OleDbData.TestB.sql rename to __tests__/Read-OleDbDataTests/Read-OleDbData.TestB.sql diff --git a/__tests__/Read-OleDbData.TestC.sql b/__tests__/Read-OleDbDataTests/Read-OleDbData.TestC.sql similarity index 100% rename from __tests__/Read-OleDbData.TestC.sql rename to __tests__/Read-OleDbDataTests/Read-OleDbData.TestC.sql diff --git a/__tests__/Read-OleDbData.TestD.sql b/__tests__/Read-OleDbDataTests/Read-OleDbData.TestD.sql similarity index 100% rename from __tests__/Read-OleDbData.TestD.sql rename to __tests__/Read-OleDbDataTests/Read-OleDbData.TestD.sql diff --git a/__tests__/Read-OleDbData.TestE.sql b/__tests__/Read-OleDbDataTests/Read-OleDbData.TestE.sql similarity index 100% rename from __tests__/Read-OleDbData.TestE.sql rename to __tests__/Read-OleDbDataTests/Read-OleDbData.TestE.sql diff --git a/__tests__/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 similarity index 81% rename from __tests__/Read-OleDbData.Tests.ps1 rename to __tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index c0b10bc..7c2b141 100644 --- a/__tests__/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -1,10 +1,13 @@ -Describe "Read-OleDbData" { - BeforeAll{ - $tfp = (Get-ChildItem Read-OleDbData.xlsx).fullname # test file path +#Requires -Modules Pester +Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force +Describe "All tests for Read-OleDbData" -Tag "Read-OleDbData" { + BeforeAll { + $scriptPath = $PSScriptRoot + $tfp = "$scriptPath\Read-OleDbData.xlsx" $cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" } Context "When Read-OleDbData.xlsx and we want sheet1 a1" { - BeforeAll{ + BeforeAll { $sql = "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql } @@ -19,7 +22,7 @@ Describe "Read-OleDbData" { } } Context "When Read-OleDbData.xlsx and we want sheet2 a1" { - BeforeAll{ + BeforeAll { $sql = "select ROUND(F1) as [A1] from [sheet2`$A1:A1]" $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql } @@ -34,9 +37,8 @@ Describe "Read-OleDbData" { } } Context "When Read-OleDbData.xlsx and we want a1 on sheet3 and sql is in a file" { - BeforeAll{ - $sql = Get-Content .\Read-OleDbData.TestA.sql -raw - $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + BeforeAll { + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestA.sql" -raw) } It "should be PSCustomObject" { $Results.GetType().Name | Should -Be 'PSCustomObject' @@ -49,9 +51,8 @@ Describe "Read-OleDbData" { } } Context "When Read-OleDbData.xlsx, we want a1 on sheets1-7, want to validate the values match properly, and sql is in a file" { - BeforeAll{ - $sql = Get-Content .\Read-OleDbData.TestB.sql -raw - $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + BeforeAll { + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestB.sql" -raw) } It "should be PSCustomObject" { $Results[0].GetType().Name | Should -Be 'PSCustomObject' @@ -65,23 +66,20 @@ Describe "Read-OleDbData" { } } Context "When Read-OleDbData.xlsx, select range sheet1 A1:E10, and sql is in a file" { - #note, this spreadsheet doesn't have the fields populated other than A1, so it will, correctly, return only one value - BeforeAll{ - $sql = Get-Content .\Read-OleDbData.TestC.sql -raw - $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + BeforeAll { + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestC.sql" -raw) } It "should be PSCustomObject" { $Results.GetType().Name | Should -Be 'PSCustomObject' } + #note, this spreadsheet doesn't have the fields populated other than A1, so it will, correctly, return only one value It "should have length of 1" { @($Results).length | Should -Be 1 } } Context "When Read-OleDbData.xlsx, select a1 from all sheets as a single record, and sql is in a file" { - #note, this spreadsheet doesn't have the fields populated other than A1, so it will, correctly, return only one value - BeforeAll{ - $sql = Get-Content .\Read-OleDbData.TestD.sql -raw - $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + BeforeAll { + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestD.sql" -raw) } It "should be PSCustomObject" { $Results.GetType().Name | Should -Be 'PSCustomObject' @@ -94,10 +92,8 @@ Describe "Read-OleDbData" { } } Context "When Read-OleDbData.xlsx, select a1 from all sheets as a single record multiple times to create a range, and sql is in a file" { - #note, this spreadsheet doesn't have the fields populated other than A1, so it will, correctly, return only one value - BeforeAll{ - $sql = Get-Content .\Read-OleDbData.TestE.sql -raw - $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql + BeforeAll { + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestE.sql" -raw) } It "should be Object[]" { $Results.GetType().Name | Should -Be 'Object[]' diff --git a/__tests__/Read-OleDbData.xlsx b/__tests__/Read-OleDbDataTests/Read-OleDbData.xlsx similarity index 100% rename from __tests__/Read-OleDbData.xlsx rename to __tests__/Read-OleDbDataTests/Read-OleDbData.xlsx From 91a124040890cdfc3083e1cf0d88f0c30ead9802 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Sat, 30 Oct 2021 11:20:27 -0400 Subject: [PATCH 011/140] add skip test check for ace --- .../Read-OleDbData.Tests.ps1 | 120 ++++++------------ 1 file changed, 42 insertions(+), 78 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 7c2b141..6af536e 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -1,108 +1,72 @@ #Requires -Modules Pester Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force -Describe "All tests for Read-OleDbData" -Tag "Read-OleDbData" { - BeforeAll { - $scriptPath = $PSScriptRoot - $tfp = "$scriptPath\Read-OleDbData.xlsx" - $cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" +$scriptPath = $PSScriptRoot +$tfp = "$scriptPath\Read-OleDbData.xlsx" +$cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" +$ACEnotWorking = $false +try { + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" +} +catch { + $ACEnotWorking = $true +} +Describe "Read-OleDbData" -Tag "Read-OleDbData" { + $PSDefaultParameterValues = @{ 'It:Skip' = $ACEnotWorking } + Context "Basic Tests" { + It "should be able to open spreadsheet" { + $null = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" + $true | Should -Be $true + } + It "should return PSCustomObject for single result" { + #multiple records will come back as Object[], but not going to test for that + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" + $Results.GetType().Name | Should -Be 'PSCustomObject' + } } - Context "When Read-OleDbData.xlsx and we want sheet1 a1" { - BeforeAll { + Context "Sheet1`$A1" { + It "Should return 1 result with a value of 1" { $sql = "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql - } - It "should be PSCustomObject" { - $Results.GetType().Name | Should -Be 'PSCustomObject' - } - It "should have length of 1" { - @($Results).length | Should -Be 1 - } - It "should be value of 1" { - $Results.A1 | Should -Be 1 + @($Results).length + $Results.A1 | Should -Be 2 } } - Context "When Read-OleDbData.xlsx and we want sheet2 a1" { - BeforeAll { + Context "Sheet2`$A1" { + It "Should return 1 result with value of 2" { $sql = "select ROUND(F1) as [A1] from [sheet2`$A1:A1]" $Results = Read-OleDbData -ConnectionString $cs -SqlStatement $sql - } - It "should be PSCustomObject" { - $Results.GetType().Name | Should -Be 'PSCustomObject' - } - It "should have length of 1" { - @($Results).length | Should -Be 1 - } - It "should be value of 2" { - $Results.A1 | Should -Be 2 + @($Results).length + $Results.A1 | Should -Be 3 } } - Context "When Read-OleDbData.xlsx and we want a1 on sheet3 and sql is in a file" { - BeforeAll { + Context "Sheet3`$A1, Sql from file" { + It "Should return 1 result with value of 3" { $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestA.sql" -raw) - } - It "should be PSCustomObject" { - $Results.GetType().Name | Should -Be 'PSCustomObject' - } - It "should have length of 1" { - @($Results).length | Should -Be 1 - } - It "should be value of 2" { - $Results.A1 | Should -Be 3 + @($Results).length + $Results.A1 | Should -Be 4 } } - Context "When Read-OleDbData.xlsx, we want a1 on sheets1-7, want to validate the values match properly, and sql is in a file" { - BeforeAll { + Context "Sheets[1-7]`$A1, Sql from file" { + It "Should return 7 result with where sum values 1-6 = value 7" { $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestB.sql" -raw) - } - It "should be PSCustomObject" { - $Results[0].GetType().Name | Should -Be 'PSCustomObject' - } - It "should have length of 7" { - @($Results).length | Should -Be 7 - } - It "should have data where sum of all initial records match the value of the last record" { $a = $Results.A1 - ($a[0..5] | Measure-Object -sum).sum | Should -Be $a[6] + $a.length + ($a[0..5] | Measure-Object -sum).sum | Should -Be (7+$a[6]) } } - Context "When Read-OleDbData.xlsx, select range sheet1 A1:E10, and sql is in a file" { - BeforeAll { - $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestC.sql" -raw) - } - It "should be PSCustomObject" { - $Results.GetType().Name | Should -Be 'PSCustomObject' - } + Context "Sheet1`$:A1:E10, Sql from file" { #note, this spreadsheet doesn't have the fields populated other than A1, so it will, correctly, return only one value - It "should have length of 1" { - @($Results).length | Should -Be 1 + It "Should return 1 result with value of 1" { + $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestC.sql" -raw) + @($Results).length + $Results.F1 | Should -Be 2 } } Context "When Read-OleDbData.xlsx, select a1 from all sheets as a single record, and sql is in a file" { - BeforeAll { + It "should return one row with 8 columns" { $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestD.sql" -raw) - } - It "should be PSCustomObject" { - $Results.GetType().Name | Should -Be 'PSCustomObject' - } - It "should have length of 1" { - @($Results).length | Should -Be 1 - } - It "should have 8 properties" { - @($Results.psobject.Properties).length | Should -Be 8 + @($Results).length + @($Results.psobject.Properties).length | Should -Be 9 } } Context "When Read-OleDbData.xlsx, select a1 from all sheets as a single record multiple times to create a range, and sql is in a file" { - BeforeAll { + It "should return 4 records with 5 columns" { $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestE.sql" -raw) - } - It "should be Object[]" { - $Results.GetType().Name | Should -Be 'Object[]' - } - It "should have length of 4" { - @($Results).length | Should -Be 4 - } - It "should have 5 properties on first record" { - @($Results[0].psobject.Properties).length | Should -Be 5 + @($Results).length + @($Results[0].psobject.Properties).length | Should -Be 9 } } } From 5e7b404dafe6c47c636002e9cda9ffc7322a63e6 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Wed, 3 Nov 2021 10:35:22 -0400 Subject: [PATCH 012/140] Add helper method --- Public/Read-OleDbData.ps1 | 3 +- Public/Read-XlsxUsingOleDb.ps1 | 47 +++++++++++++++++++ .../Read-OleDbData.Tests.ps1 | 4 +- .../Read-XlsxUsingOleDb.Tests..ps1 | 20 ++++++++ 4 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 Public/Read-XlsxUsingOleDb.ps1 create mode 100644 __tests__/Read-OleDbDataTests/Read-XlsxUsingOleDb.Tests..ps1 diff --git a/Public/Read-OleDbData.ps1 b/Public/Read-OleDbData.ps1 index 579d904..ccd0fdc 100644 --- a/Public/Read-OleDbData.ps1 +++ b/Public/Read-OleDbData.ps1 @@ -26,7 +26,6 @@ function Read-OleDbData { ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=file.xlsx;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" } $Results = Read-OleDbData @ReadDataArgs - #> param( [Parameter(Mandatory)] @@ -61,7 +60,7 @@ function Read-OleDbData { # and get rid of the extra fields that come back with the datatable or rows. $DataTable = new-object System.Data.DataTable - $DataAdapter = new-object System.Data.OleDb.OleDbDataAdapter $SqlStatement,$ConnectionString + $DataAdapter = new-object System.Data.OleDb.OleDbDataAdapter $SqlStatement, $ConnectionString $null = $DataAdapter.Fill($DataTable) $null = $DataAdapter.Dispose() $DataTable.Rows | Select-Object $DataTable.Columns.ColumnName diff --git a/Public/Read-XlsxUsingOleDb.ps1 b/Public/Read-XlsxUsingOleDb.ps1 new file mode 100644 index 0000000..0d75f41 --- /dev/null +++ b/Public/Read-XlsxUsingOleDb.ps1 @@ -0,0 +1,47 @@ +#Requires -Version 5 +function Read-XlsxUsingOleDb { + <# + .SYNOPSIS + Helper method for executing Read-OleDbData with some basic defaults. + + For additional help, see documentation for Read-OleDbData cmdlet. + + .DESCRIPTION + Uses Read-OleDbData to execute a sql statement against a xlsx file. For finer grained control over the interaction, you may use that cmdlet. This cmdlet assumes a file path will be passed in and the connection string will be built with no headers and treating all results as text. + + Running this command is equivalent to running the following: + + $FullName = (Get-ChildItem $Path).FullName + Read-OleDbData ` + -ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$FullName;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" ` + -SqlStatement $Query + + .EXAMPLE + Read-XlsxUsingOleDb .\test.xlsx 'select ROUND(F1) as [A1] from [sheet3$A1:A1]' + + .EXAMPLE + $Path = (Get-ChildItem 'test.xlsx').FullName + $Query = "select ROUND(F1) as [A] from [sheet1$A1:A1]" + Read-XlsxUsingOleDb -Path $Path -Query $Query + + .EXAMPLE + $ReadDataArgs = @{ + Path = .\test.xlsx + Query = Get-Content query.sql -Raw + } + $Results = Read-XlsxUsingOleDb @ReadDataArgs + #> + param( + #The path to the file to open. + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [String] $Path, # var name consistent with Import-Excel + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [String] $Query # var name consistent with Invoke-Sqlcmd + ) + $FullName = (Get-ChildItem $Path).FullName + Read-OleDbData ` + -ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$FullName;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" ` + -SqlStatement $Query +} \ No newline at end of file diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 6af536e..1abb368 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -47,7 +47,7 @@ Describe "Read-OleDbData" -Tag "Read-OleDbData" { It "Should return 7 result with where sum values 1-6 = value 7" { $Results = Read-OleDbData -ConnectionString $cs -SqlStatement (Get-Content "$scriptPath\Read-OleDbData.TestB.sql" -raw) $a = $Results.A1 - $a.length + ($a[0..5] | Measure-Object -sum).sum | Should -Be (7+$a[6]) + $a.length + ($a[0..5] | Measure-Object -sum).sum | Should -Be (7 + $a[6]) } } Context "Sheet1`$:A1:E10, Sql from file" { @@ -69,4 +69,4 @@ Describe "Read-OleDbData" -Tag "Read-OleDbData" { @($Results).length + @($Results[0].psobject.Properties).length | Should -Be 9 } } -} +} \ No newline at end of file diff --git a/__tests__/Read-OleDbDataTests/Read-XlsxUsingOleDb.Tests..ps1 b/__tests__/Read-OleDbDataTests/Read-XlsxUsingOleDb.Tests..ps1 new file mode 100644 index 0000000..d88ec4b --- /dev/null +++ b/__tests__/Read-OleDbDataTests/Read-XlsxUsingOleDb.Tests..ps1 @@ -0,0 +1,20 @@ +#Requires -Modules Pester +$scriptPath = $PSScriptRoot +Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force +$tfp = "$scriptPath\Read-OleDbData.xlsx" +$ACEnotWorking = $false +try { + $Results = Read-XlsxUsingOleDb $tfp "select 1" +} +catch { + $ACEnotWorking = $true +} +Describe "Read-XlsxUsingOleDb" -Tag "Read-XlsxUsingOleDb" { + $PSDefaultParameterValues = @{ 'It:Skip' = $ACEnotWorking } + Context "Sheet1`$A1" { + It "Should return 1 result with a value of 1" { + $Results = Read-XlsxUsingOleDb $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" + @($Results).length + $Results.A1 | Should -Be 2 + } + } +} From 62c8d74a59cf721685e95171b6b1adf4a95e958a Mon Sep 17 00:00:00 2001 From: muschebubusche <65829739+muschebubusche@users.noreply.github.com> Date: Tue, 26 Oct 2021 19:01:25 +0200 Subject: [PATCH 013/140] Add selective column import --- Public/Import-Excel.ps1 | 60 ++++++- __tests__/ImportExcelHeaderName.tests.ps1 | 180 +++++++++++++++++--- __tests__/testImportExcel.xlsx | Bin 0 -> 2635 bytes __tests__/testImportExcelHeaderOnly.xlsx | Bin 0 -> 2579 bytes __tests__/testImportExcelImportColumns.xlsx | Bin 0 -> 2655 bytes __tests__/testImportExcelSparse.xlsx | Bin 0 -> 2666 bytes 6 files changed, 218 insertions(+), 22 deletions(-) create mode 100644 __tests__/testImportExcel.xlsx create mode 100644 __tests__/testImportExcelHeaderOnly.xlsx create mode 100644 __tests__/testImportExcelImportColumns.xlsx create mode 100644 __tests__/testImportExcelSparse.xlsx diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index f020979..6e4b3bf 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -35,7 +35,8 @@ [string[]]$AsText, [string[]]$AsDate, [ValidateNotNullOrEmpty()] - [String]$Password + [String]$Password, + [Int[]]$ImportColumns ) end { $sw = [System.Diagnostics.Stopwatch]::StartNew() @@ -92,6 +93,26 @@ throw "Failed creating property names: $_" ; return } } + function Clear-ExcelPackage { + <# + .SYNOPSIS + Clear given ExcelPackage from specified columns. + #> + param ( + # Column from where the cleaning will start. + [Parameter(Mandatory)] + [Int] + $Start, + # Count of columns that will be removed. + [Parameter(Mandatory)] + [Int] + $Count + ) + + $Worksheet.DeleteColumn($Start, $Count) + # Return $ExcelPackage to update the variable + return $ExcelPackage + } foreach ($Path in $Paths) { if ($path) { $extension = [System.IO.Path]::GetExtension($Path) @@ -141,7 +162,42 @@ $columns = ($StartColumn..$EndColumn).Where( { $colHash[$_] }) } else { - $Columns = $StartColumn .. $EndColumn ; if ($StartColumn -gt $EndColumn) { Write-Warning -Message "Selecting columns $StartColumn to $EndColumn might give odd results." } + if ($ImportColumns) { + $end = $Worksheet.Dimension.End.Column + if (($StartColumn -ne 1) -or ($EndColumn -ne $end)) { Write-Warning -Message "If ImportColumns is set than individual StartColumn and EndColumn will be ignored." } + # Variable to store all removed columns + $removedColumns = 0 + # Preparation run + $start = 1 + $count = $ImportColumns[0] - 1 + $ExcelPackage = Clear-ExcelPackage -Start $start -Count $count + $removedColumns = $removedColumns + $count + for ($i = 0; $i -lt $ImportColumns.Count; $i++) { + # Check if the current iteration is the last one for cleanup meassures + if ($i -eq ($ImportColumns.Count - 1)) { $lastLoop = $true } + if ($lastLoop) { + # Only clean up if the endcolumn does not match the last entry in the $ImportColumns array + if ($ImportColumns[$i] -ne $end) { + $start = $ImportColumns.Count + 1 + $count = $end - ($removedColumns + $ImportColumns.Count) + } else { + # This means that the endcolumn gets imported + continue + } + } else { + # Calculate the StartColumn and ColumnCount for the removal + $start = ($i + 1) + 1 # 1 is from the preparation run + $count = $ImportColumns[$i + 1] - ($removedColumns + $start) + $removedColumns = $removedColumns + $count + } + $ExcelPackage = Clear-ExcelPackage -Start $start -Count $count + } + # Create new array out of the $ImportColumns.Count for the further processing + $columns = 1..$ImportColumns.Count + } + else { + $Columns = $StartColumn .. $EndColumn ; if ($StartColumn -gt $EndColumn) { Write-Warning -Message "Selecting columns $StartColumn to $EndColumn might give odd results." } + } if ($NoHeader) { $rows = $StartRow..$EndRow ; if ($StartRow -gt $EndRow) { Write-Warning -Message "Selecting rows $StartRow to $EndRow might give odd results." } } elseif ($HeaderName) { $rows = $StartRow..$EndRow } else { diff --git a/__tests__/ImportExcelHeaderName.tests.ps1 b/__tests__/ImportExcelHeaderName.tests.ps1 index 0594a88..85ae5a5 100644 --- a/__tests__/ImportExcelHeaderName.tests.ps1 +++ b/__tests__/ImportExcelHeaderName.tests.ps1 @@ -1,33 +1,66 @@ +#Requires -Modules Pester + +if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) { + Import-Module $PSScriptRoot\..\ImportExcel.psd1 +} Describe "Import-Excel on a sheet with no headings" { BeforeAll { - $xlfile = "TestDrive:\testImportExcel.xlsx" - $xlfileHeaderOnly = "TestDrive:\testImportExcelHeaderOnly.xlsx" - $xl = "" | Export-excel $xlfile -PassThru + $xlfile = "$PSScriptRoot\testImportExcel.xlsx" + $xlfileHeaderOnly = "$PSScriptRoot\testImportExcelHeaderOnly.xlsx" + $xlfileImportColumns = "$PSScriptRoot\testImportExcelImportColumns.xlsx" - Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A' - Set-ExcelRange -Worksheet $xl.Sheet1 -Range B1 -Value 'B' - Set-ExcelRange -Worksheet $xl.Sheet1 -Range C1 -Value 'C' + # Create $xlfile if it does not exist + if (!(Test-Path -Path $xlfile)) { + $xl = "" | Export-excel $xlfile -PassThru - Set-ExcelRange -Worksheet $xl.Sheet1 -Range A2 -Value 'D' - Set-ExcelRange -Worksheet $xl.Sheet1 -Range B2 -Value 'E' - Set-ExcelRange -Worksheet $xl.Sheet1 -Range C2 -Value 'F' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range B1 -Value 'B' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range C1 -Value 'C' + + Set-ExcelRange -Worksheet $xl.Sheet1 -Range A2 -Value 'D' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range B2 -Value 'E' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range C2 -Value 'F' + + Set-ExcelRange -Worksheet $xl.Sheet1 -Range A3 -Value 'G' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range B3 -Value 'H' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range C3 -Value 'I' + + Close-ExcelPackage $xl + } - Set-ExcelRange -Worksheet $xl.Sheet1 -Range A3 -Value 'G' - Set-ExcelRange -Worksheet $xl.Sheet1 -Range B3 -Value 'H' - Set-ExcelRange -Worksheet $xl.Sheet1 -Range C3 -Value 'I' + # Create $xlfileHeaderOnly if it does not exist + if (!(Test-Path -Path $xlfileHeaderOnly)) { + $xl = "" | Export-excel $xlfileHeaderOnly -PassThru - Close-ExcelPackage $xl + Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range B1 -Value 'B' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range C1 -Value 'C' - # crate $xlfileHeaderOnly - $xl = "" | Export-excel $xlfileHeaderOnly -PassThru + Close-ExcelPackage $xl + } - Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A' - Set-ExcelRange -Worksheet $xl.Sheet1 -Range B1 -Value 'B' - Set-ExcelRange -Worksheet $xl.Sheet1 -Range C1 -Value 'C' + # Create $xlfileImportColumns if it does not exist + if (!(Test-Path -Path $xlfileImportColumns)) { + $xl = "" | Export-Excel $xlfileImportColumns -PassThru - Close-ExcelPackage $xl + Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'A' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range B1 -Value 'B' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range C1 -Value 'C' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range D1 -Value 'D' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range E1 -Value 'E' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range F1 -Value 'F' + + Set-ExcelRange -Worksheet $xl.Sheet1 -Range A2 -Value '1' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range B2 -Value '2' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range C2 -Value '3' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range D2 -Value '4' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range E2 -Value '5' + Set-ExcelRange -Worksheet $xl.Sheet1 -Range F2 -Value '6' + + Close-ExcelPackage $xl + } } It "Import-Excel should have this shape" { @@ -167,7 +200,7 @@ Describe "Import-Excel on a sheet with no headings" { } It "Should" { - $xlfile = "TestDrive:\testImportExcelSparse.xlsx" + $xlfile = "$PSScriptRoot\testImportExcelSparse.xlsx" $xl = "" | Export-excel $xlfile -PassThru Set-ExcelRange -Worksheet $xl.Sheet1 -Range A1 -Value 'Chuck' @@ -224,4 +257,111 @@ Describe "Import-Excel on a sheet with no headings" { $actual[0].P2 | Should -Be 'B' $actual[0].P3 | Should -Be 'C' } + + It "Should import correct data if -ImportColumns is used with the first column" { + $actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(1,2,4,5)) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 4 + $actualNames[0] | Should -Be 'A' + $actualNames[2] | Should -Be 'D' + + $actual.Count | Should -Be 1 + $actual[0].A | Should -Be 1 + $actual[0].B | Should -Be 2 + $actual[0].D | Should -Be 4 + $actual[0].E | Should -Be 5 + } + + It "Should import correct data if -ImportColumns is used with the first column" { + $actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(1,3,4,5)) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 4 + $actualNames[0] | Should -Be 'A' + $actualNames[2] | Should -Be 'D' + + $actual.Count | Should -Be 1 + $actual[0].A | Should -Be 1 + $actual[0].C | Should -Be 3 + $actual[0].D | Should -Be 4 + $actual[0].E | Should -Be 5 + } + + It "Should import correct data if -ImportColumns is used without the first column" { + $actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(2,3,6)) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 3 + $actualNames[0] | Should -Be 'B' + $actualNames[2] | Should -Be 'F' + + $actual.Count | Should -Be 1 + $actual[0].B | Should -Be 2 + $actual[0].C | Should -Be 3 + $actual[0].F | Should -Be 6 + } + + It "Should import correct data if -ImportColumns is used without the first column" { + $actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(2,5,6)) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 3 + $actualNames[0] | Should -Be 'B' + $actualNames[2] | Should -Be 'F' + + $actual.Count | Should -Be 1 + $actual[0].B | Should -Be 2 + $actual[0].E | Should -Be 5 + $actual[0].F | Should -Be 6 + } + + It "Should import correct data if -ImportColumns is used with only 1 column" { + $actual = @(Import-Excel $xlfile -ImportColumns @(2)) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 1 + $actualNames[0] | Should -Be 'B' + + $actual.Count | Should -Be 2 + $actual[0].B | Should -Be 'E' + } + + It "Should import correct data if -ImportColumns is used with only 1 column which is also the last" { + $actual = @(Import-Excel $xlfile -ImportColumns @(3)) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 1 + $actualNames[0] | Should -Be 'C' + + $actual.Count | Should -Be 2 + $actual[1].C | Should -Be 'I' + } + + It "Should import correct data if -ImportColumns contains all columns" { + $actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(1,2,3,4,5,6)) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 6 + $actualNames[0] | Should -Be 'A' + $actualNames[2] | Should -Be 'C' + + $actual.Count | Should -Be 1 + $actual[0].A | Should -Be 1 + $actual[0].B | Should -Be 2 + $actual[0].C | Should -Be 3 + $actual[0].D | Should -Be 4 + $actual[0].E | Should -Be 5 + $actual[0].F | Should -Be 6 + } + + It "Should ignore -StartColumn and -EndColumn if -ImportColumns is set aswell" { + $actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(5) -StartColumn 2 -EndColumn 7) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 1 + $actualNames[0] | Should -Be 'E' + + $actual[0].E | Should -Be '5' + } } \ No newline at end of file diff --git a/__tests__/testImportExcel.xlsx b/__tests__/testImportExcel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9f975792e091fbdb8d502ecaaa9baf3ae7a7bc94 GIT binary patch literal 2635 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 literal 0 HcmV?d00001 diff --git a/__tests__/testImportExcelImportColumns.xlsx b/__tests__/testImportExcelImportColumns.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..be83bff2147a392d257522da6bedeb04168e0b07 GIT binary patch literal 2655 zcmZ`*2{csuA0G{4muxYFMx_WdnJ7;p$}(P!u|4Z#7~90yvP>_LG9iR4*|YS7B$<>p z!&v5-p2(6VO@uLpqD+!{cl1Ah!+Y<0&$+*I&$-{%%r65H0xrXwp0;l- zZrzsW1A%nGAdoZ&1adJY28Q7S!?1QyLHJNN?Z|*rl=LnuFha5oi>KS?)+?Kp4J%hF z+t(U3 z)C`wyNmDoz*W{p-Mhih;RirVt-e5|J&+!PWwApSjJqIpRo-_!~CX80_lSCEm23|}j z_aNYq!Vk>tatmkPpPahylsp%AT2pnW&;B4Prqvp`nG8$0+Tyn25valtX1oeR5Az2=Nz zj(kI%|5iSE7<;MVn?`yiKHNldtkl%N9HEhYd3Jkg)P!r+H$!SyJWyqRxFX;ZQd@wmJsZ8GGHnOpw4oGSoRMwAaj!lHXAhBMa`e zk7~7S3zPav7041(fEa0@pjqC!YDYz{R3vOPASUKZ#Eb*AwHC>u}`N+IwI>KRGbDHjHG5?@aFTMNbRsB|K z%9hFcA6~6#HlKrytw*2PxDSHdY-*s+Ae1#;vN^tSUme( znSVeJJjzkXzSR0h=8L(#jJG4&Ee%1c`+rIF9~@Z$aXH~dzMhj2n7Af z$xropnOSwht+XyKJ!EVv>&b!Xlb3B8vJouGIc4LQR!X@q+j@p3W(ax?nBAV_!V6xX zR*b4Az7mvr6ZUZs^1hW&839E%6$3DNrTvBGZaFatvV2FAnb^C&5ER(T$>X)U!^JHx zW42lno$r1|!WYF2)se@G9hg_mtTy;8D}&(~m035LwK?Jr)mE%{OFIlP!P zTDqdNr=vjVY|2tcp@oP{s5y>lfLn3Ptwfu=&UP}y#N(lVV%>j@{`z#RNCi5F$QZWN zCKtLe+Mn+GIyqD&%4LU_gZ1pRJ23f70k`Z05=VZ`F`>SAd|0T?>VjCcPC6A62bYY; z?#y^7ZsI}^WZ7w!>bJ*ngiv%Dsa=*ybCXo_d0E#AQ_+u1t=QCa9GAuA1x@F3y|M?- z-@#Pn%sUwiS6EMBW^kmS*1q(bjEX*QA_`B-Ic5t@VnMNN~kSRbY|vtQFZbw`ifE zIbp}X#+?VGQf9nfd9>`gb5?Imu1GmU6=zctvje8moZ(Xm_FmgzlW3tO!+)`a_oHN z5j4caBkC{>QZHQI4RVgJ87~`1yu@18bb-#j!fa1@vu$+HzKMp0vQS%n6yj^^slHmM zUHYGB@(7hIC)!qGPYsNaRI;UNfg|Sh1q;rUP#fwL8NXP=}d!+2BV83o+>ylao7(Yk$=G3 z|0JclNtN;-DU86JKkfd$sg|GJd_`C>QZ?>iWc%J5b_t5Cqiv5VBa1nkbQUhzX%85d ztL{9m-#LEa`na-9&&hX{LqjsKSic2pj5h(U+d8L^`UAbIBx3A!f$ZFS;+MG1;^yK- z(Bsg*pbk)faU!%Ist3KNQ#*nEzB(;=k)ct1o3sFY|MepR0OzTH`7PPF0q>0B4&1eJ z0*K@pzZ)BQgPc3U*2)+-85;)L#%A7}<7WL@*#Y?mH2+8PZ`_CXm~vBbtwQ+!{}KPl z$c?-3nu>d**J@c{b(ggRzOj{88?NitDnsyR>qZZvQ34R|TY|vV3{XrK;y(Qi0?03t literal 0 HcmV?d00001 diff --git a/__tests__/testImportExcelSparse.xlsx b/__tests__/testImportExcelSparse.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..099cbf7a8c72f059fdd9559be3fc81252573df38 GIT binary patch literal 2666 zcmZ{m2|UyPAIHaBF>)nWQ=^oHO=EIP2j-Z$T9Ti!kYnYxB1c&WIVVMObj*=6$FF1= zk@a&%;V0%+Q3<)~x9R`*8~^|B{e3+4dF=7n`}5fQ`Fg$I?=Kn!r96HpS znBveWYy=y|HQ31}(R|@fa$*?k^T4WHH;W+Cq}fhjYX(fbAnrYo>^by^izpyt)7L#6 z-vx*9WPcgnCozBd(;t&H*!a1q0O;QRZt54Qm?ksCP7)*`wb60i*+-7PgFYs3{Jeh^ ziFjvf29fg!p`b%fZ0#L>0m1cQ;}6Vasmdo~PQrTR%Y(}8rm4~J@7!wo5vnCK!#$_y z151+C1#UF_Gp5zEjjG#4m66F zj~yR+3)qbQk8veTpo&bm0?gCN7w_e#s>1q=Z>I`H!azL3_E;i0g4YEU6$c-=@P%W- zj)$Wce}|timw?j=_F7q5?Jhqz5u@8liYN+)v_;&v&FA&x8tiYI zk8MbkNwdG`3Y9w@B*XO`UMDtbxS-i~E6M1N#-3$tGlJNdWs`?!Sqcdo{@EQ~+$ycy zfUE=bmI(bSd;F2-x*H}@%6rY~YnpNScb>d(JVW){XqG!&l>eF1@&t88kX0soFt_CX#6b?s}>A8f3%5lMX|p~rtNDww_) z`V-96rvV&Vk|N(|dYINdcbGmlsM1({aj&{|?1lG(>i`xL_R6<1iNGc2_A*%@H~|3Z z-%Nh1&rW8;3B^h6EIcHqrm1?(=|65-Rg>XURae0V?@VPg-!*sjkAL>mu)`d5A!T24 z{l2bOG``{~+Y_U<1ebKDNQ-mJILc`ON$an=p$8>ELL|wShU1`*Z+%ffQ>^m`MZ4=F z@4|PR5YALAARzW|tAncEba_(`zlUP|@`3rg1J-lr?{ZX|RbArw)~uehXr243)Ma2X zeJF2T_E1X}UueQ|OSUn;xZf$?`@gQpCb zsF1Q9=&xR=txWV63b5#~GuTQ;ul!`9KGQAQ%!wnp=@>tEJl@|=b>o0JJK`%T02@l_hV_{tCaW9 z$5{WIN&_kDt0PvNYK>=GT+AG-2X#BlMHe1f)N#RR49pW-Gn7lFx{DU{{sb{X&{*3( zhf-VS7~pzZ91G#Hy37gL*oI_!p1Da(v0i}O_eoB|9mK;$&rtA$35 z$*@FVN4-@98@I+KN2Ul2rbPvRi{R%U;)VBPk-v^XF7&q=&&P?_7SGnq zpmaF@yi8lAT!aY_We;+XEx%3+2EZ(_6a5jU42^#Dcu>aE^cCMc?@71X`je5AV`v^j z=Ma4wPvwq+PQaPylF|IW*c(%;PzUL`zcKp~M)nN7w{4)IrKeE4-K3&RE2-|vr~}CF zG)cJJ$@gf7SCgR1Do=$Tt?5o$@0Y^21`fverhUWx0(Dw#*Q8F2c%!cH-Nua%+&l}g z|K-?vCs1s4KB>ITtvGCBbgR786kv+DmZB zB2bd?n4Z)Q&c0{yrvogv<;a7VVV{Y9L7TSGG3h!jc$bOcdX{Fs; zkya)8SGll<#UfEsNW;YyX6;b~_Gv&Q%*8i5&2qyv1xLFcAl=k8FN^5=wj~zy9(2&g z#fI)ks4)lgg&+@j9r4a1w-p@yHNR99gI=-5t@6G^vaHEoC>q7Vsmv_*-`+`>9N6Oj zyrFErfPG!DcJF3jnOxa6@%BXanaZKCzi&@v*M?=n%}C_^ox0tUXcRXO>sP$Y M=Oq(yG9T;PKU+CKg#Z8m literal 0 HcmV?d00001 From 85f2433ffc99b240c6e75b119b731c0a0be7d279 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Thu, 4 Nov 2021 10:44:14 -0400 Subject: [PATCH 014/140] Rename helper function to make it more helpful. =) --- Public/{Read-XlsxUsingOleDb.ps1 => Invoke-ExcelQuery.ps1} | 8 ++++---- ...xUsingOleDb.Tests..ps1 => Invoke-ExcelQuery.Tests.ps1} | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) rename Public/{Read-XlsxUsingOleDb.ps1 => Invoke-ExcelQuery.ps1} (89%) rename __tests__/Read-OleDbDataTests/{Read-XlsxUsingOleDb.Tests..ps1 => Invoke-ExcelQuery.Tests.ps1} (67%) diff --git a/Public/Read-XlsxUsingOleDb.ps1 b/Public/Invoke-ExcelQuery.ps1 similarity index 89% rename from Public/Read-XlsxUsingOleDb.ps1 rename to Public/Invoke-ExcelQuery.ps1 index 0d75f41..00fb4a0 100644 --- a/Public/Read-XlsxUsingOleDb.ps1 +++ b/Public/Invoke-ExcelQuery.ps1 @@ -1,5 +1,5 @@ #Requires -Version 5 -function Read-XlsxUsingOleDb { +function Invoke-ExcelQuery { <# .SYNOPSIS Helper method for executing Read-OleDbData with some basic defaults. @@ -17,7 +17,7 @@ function Read-XlsxUsingOleDb { -SqlStatement $Query .EXAMPLE - Read-XlsxUsingOleDb .\test.xlsx 'select ROUND(F1) as [A1] from [sheet3$A1:A1]' + Invoke-ExcelQuery .\test.xlsx 'select ROUND(F1) as [A1] from [sheet3$A1:A1]' .EXAMPLE $Path = (Get-ChildItem 'test.xlsx').FullName @@ -29,7 +29,7 @@ function Read-XlsxUsingOleDb { Path = .\test.xlsx Query = Get-Content query.sql -Raw } - $Results = Read-XlsxUsingOleDb @ReadDataArgs + $Results = Invoke-ExcelQuery @ReadDataArgs #> param( #The path to the file to open. @@ -41,7 +41,7 @@ function Read-XlsxUsingOleDb { [String] $Query # var name consistent with Invoke-Sqlcmd ) $FullName = (Get-ChildItem $Path).FullName - Read-OleDbData ` + Invoke-ExcelQuery ` -ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$FullName;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" ` -SqlStatement $Query } \ No newline at end of file diff --git a/__tests__/Read-OleDbDataTests/Read-XlsxUsingOleDb.Tests..ps1 b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 similarity index 67% rename from __tests__/Read-OleDbDataTests/Read-XlsxUsingOleDb.Tests..ps1 rename to __tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 index d88ec4b..3d0842f 100644 --- a/__tests__/Read-OleDbDataTests/Read-XlsxUsingOleDb.Tests..ps1 +++ b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 @@ -4,16 +4,16 @@ Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force $tfp = "$scriptPath\Read-OleDbData.xlsx" $ACEnotWorking = $false try { - $Results = Read-XlsxUsingOleDb $tfp "select 1" + $Results = Invoke-ExcelQuery $tfp "select 1" } catch { $ACEnotWorking = $true } -Describe "Read-XlsxUsingOleDb" -Tag "Read-XlsxUsingOleDb" { +Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" { $PSDefaultParameterValues = @{ 'It:Skip' = $ACEnotWorking } Context "Sheet1`$A1" { It "Should return 1 result with a value of 1" { - $Results = Read-XlsxUsingOleDb $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" + $Results = Invoke-ExcelQuery $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" @($Results).length + $Results.A1 | Should -Be 2 } } From 7a8bbb97710256a4f2eb01b0d234e0671ae3ac3b Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Thu, 4 Nov 2021 20:54:51 -0400 Subject: [PATCH 015/140] add to exported functions, formatting, fix typo. --- ImportExcel.psd1 | 2 ++ Public/Invoke-ExcelQuery.ps1 | 2 +- __tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index 8a267c3..8143435 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -64,6 +64,7 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5 'Import-USPS', 'Invoke-AllTests', 'Invoke-Sum', + 'Invoke-ExcelQuery', 'Join-Worksheet', 'LineChart', 'Merge-MultipleSheets', @@ -80,6 +81,7 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5 'Pivot', 'Read-Clipboard', 'ReadClipboardImpl', + 'Read-OleDbData', 'Remove-Worksheet', 'Select-Worksheet', 'Send-SQLDataToExcel', diff --git a/Public/Invoke-ExcelQuery.ps1 b/Public/Invoke-ExcelQuery.ps1 index 00fb4a0..f799a11 100644 --- a/Public/Invoke-ExcelQuery.ps1 +++ b/Public/Invoke-ExcelQuery.ps1 @@ -41,7 +41,7 @@ function Invoke-ExcelQuery { [String] $Query # var name consistent with Invoke-Sqlcmd ) $FullName = (Get-ChildItem $Path).FullName - Invoke-ExcelQuery ` + Read-OleDbData ` -ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$FullName;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" ` -SqlStatement $Query } \ No newline at end of file diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 1abb368..500772f 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -1,9 +1,9 @@ #Requires -Modules Pester -Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force $scriptPath = $PSScriptRoot +Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force $tfp = "$scriptPath\Read-OleDbData.xlsx" -$cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" $ACEnotWorking = $false +$cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" try { $Results = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" } From eabaab79c5e4431d522a8d0542f8549947a5747a Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 14:43:57 -0500 Subject: [PATCH 016/140] add ace check --- Public/Invoke-ExcelQuery.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Public/Invoke-ExcelQuery.ps1 b/Public/Invoke-ExcelQuery.ps1 index f799a11..3b8817e 100644 --- a/Public/Invoke-ExcelQuery.ps1 +++ b/Public/Invoke-ExcelQuery.ps1 @@ -16,6 +16,10 @@ function Invoke-ExcelQuery { -ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$FullName;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" ` -SqlStatement $Query + Note that this command uses the MICROSOFT.ACE.OLEDB provider and will not work without it. + + If needed, please download the appropriate package from https://www.microsoft.com/en-us/download/details.aspx?id=54920. + .EXAMPLE Invoke-ExcelQuery .\test.xlsx 'select ROUND(F1) as [A1] from [sheet3$A1:A1]' @@ -40,6 +44,13 @@ function Invoke-ExcelQuery { [ValidateNotNullOrEmpty()] [String] $Query # var name consistent with Invoke-Sqlcmd ) + + $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") + if($IsMissingACE){ + Write-Error "MICROSOFT.ACE.OLEDB is missing! Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" + return + } + $FullName = (Get-ChildItem $Path).FullName Read-OleDbData ` -ConnectionString "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$FullName;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" ` From aa1b0018abc216b56ab7c9ea514cfc90a108d18c Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 15:14:46 -0500 Subject: [PATCH 017/140] Add examples --- Examples/InvokeExcelQuery/Examples.ps1 | 13 +++++++++++++ Examples/InvokeExcelQuery/testOleDb.xlsx | Bin 0 -> 2955 bytes 2 files changed, 13 insertions(+) create mode 100644 Examples/InvokeExcelQuery/Examples.ps1 create mode 100644 Examples/InvokeExcelQuery/testOleDb.xlsx diff --git a/Examples/InvokeExcelQuery/Examples.ps1 b/Examples/InvokeExcelQuery/Examples.ps1 new file mode 100644 index 0000000..c565292 --- /dev/null +++ b/Examples/InvokeExcelQuery/Examples.ps1 @@ -0,0 +1,13 @@ +try {Import-Module $PSScriptRoot\..\..\ImportExcel.psd1} catch {throw ; return} + +$queries = + 'select * from [sheet1$A:A]', + 'select * from [sheet1$]', + 'select * from [sheet1$A2:E11]', + 'select F2,F5 from [sheet1$A2:E11]', + 'select * from [sheet1$A2:E11] where F2 = "Grocery"', + 'select F2 as [Category], F5 as [Discount], F5*2 as [DiscountPlus] from [sheet1$A2:E11]' + +foreach ($query in $queries) { + Invoke-ExcelQuery .\testOleDb.xlsx $query| Format-Table +} diff --git a/Examples/InvokeExcelQuery/testOleDb.xlsx b/Examples/InvokeExcelQuery/testOleDb.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..944751c9ec1543e296e4688272d7a6b35e089c93 GIT binary patch literal 2955 zcmZ{m2{@E%8^=eOtTpzXP$$g6Oty|BTWF-lU^=o)WNc$8GX|4{VvucYW6%0kiex`Z znGA8#XD3TYc12kdlbm-t-}RY%-?`uGn&+Bp=6SC7{@wrk`QJzjb`D_>7w~A9xLHq` zmpu|^1A#QyK_DRz2xM>U=S#r)5->KwSFm_TwICnwn&eIdI~>xA!M59GRm++bkI0tF z+E(Z{WpogYR}(v`YyJGRp$a7tvZSoT;~g8@TpAeJr?@W}?X6w0nK`lGn+dH^me8?* z#1#8(h%s!!r3o!fq5H!zazZF;H};xB_j7>=%2GFbdj?Fn_Y#aA~&QE`IrD0QAricdaWlRLfb-gJgw-)Mm$RXJ5Gv?v5#56E{K) znUp=ZpqYP9^RON@v3+3Txq{1}UHmT#x$26^C{tLUVr5_@dY%>qU*kM>DqOvMVWQ8h zV`M|TuF^}4O5i-M;e(!c4^I-~p`w$#wi+(?W4 zT&(zzKY`5{Uc6ln06hx81$l36FnTMUW@1iulfxf|DZC0Vur1z?;}{)&wZ!$SiDyktTVa?8 zd!KD^%b8Y!;1-QDollBm4c;I$Yq);=RT9NGTU%z+u2qxNoNH60*|rfJI`O?XtgKy9 zwMnM|G*EtE=kfhTaHKmbQNrh&)#o(x$~ACN7{R`t13_s7mstSMin2HmM-bmdGk9Q__T-+tMA<&RSBN2(#I7opss^$r$(C_Yy?tYit6(?-3;pZ za{aq3$DlU**oFi(y5(+K@A9u5Q=@9lbyp5)orv`s8r=plnXqR5Gm~(a5g{wJib!Tg?f>&C#^1oOY?o?bJ z`I0_Xv@NaNmdkZLVY4mIoJSaM<}#t{vhA2viZmRj+UcR9u#$gboGe4Po=@J9lU#e12?eX7~XwlMX9`pXuO@tb(inGVi!RAn{$r;61Qd0$%;c0{cPYmQXK_|o^a@ak`j zRh?^J-`>d)D`-7;z@93wpzCsPx;1)k{oN^+z5Rtr>m_2%Q=6%#d4hMnddgaBPb4nkYC8KQI}tWy ziGov&=?f2hudIIPnqSZ%nZ>v*>Q`E}XDkKX!s|CXePBaSM>LzFva3=!fh<*+}C0@6nfrWfzgA|#vKxU?#e6!mKvGAl_i zZx!Lg+(!I-HaBFn9FWF`4nn*<3JTqTAGg?IP`7wE1%`#O9{H64eIADKmo#okzC9f| z#CD!ryFa?<68B9)u7=a`%k^$_iSg?U*oipv2q%Oy-Krvv-z+7d$5q}^e=PUORCy6B zn;{U><-)6E{(0%VeifsaQ!8>@&&X2MCgdE=TU6-jb6)Yp$M^3WN|vP@+tTM(a?p|G z=!f$@^0l{lw1|4a)4!Oq*w42L5owTF?@ zff=>QVVGfkd@HKwk3-1{BR+KpGY>nwD@7JPJaW8m!OAe^x+_}b>;vA^_Z(lR4iXez zCb2W`lQ{j($0CF)(`9-j&H;2`$FV(|D8yK$RK9XA3;l7KveN&#E@Qzeja@)Jh(K+G z|5FzaXMe1#HNoH0*ZoI%ut~IY9P$v88ys8)Lex`a}IIZD=XKLq2C19wpXWZ98;2^#xUAs12%&j$4L)*deG# zqpPlavke<}#g?JR=fsv}njMBer=EJkLEyQACQApy#!a{86KW7dnyI}`lW*JrX zZe%q*rrqy`0nj&l%zy7@R!?C1;%?Xg( Date: Mon, 8 Nov 2021 15:25:26 -0500 Subject: [PATCH 018/140] update tests to match --- .../Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 | 11 ++++------- .../Read-OleDbDataTests/Read-OleDbData.Tests.ps1 | 11 ++++------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 index 3d0842f..4f428e2 100644 --- a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 @@ -2,15 +2,12 @@ $scriptPath = $PSScriptRoot Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force $tfp = "$scriptPath\Read-OleDbData.xlsx" -$ACEnotWorking = $false -try { - $Results = Invoke-ExcelQuery $tfp "select 1" -} -catch { - $ACEnotWorking = $true +$IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") +if($IsMissingACE){ + Write-Host "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped. Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" } Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" { - $PSDefaultParameterValues = @{ 'It:Skip' = $ACEnotWorking } + $PSDefaultParameterValues = @{ 'It:Skip' = $IsMissingACE } Context "Sheet1`$A1" { It "Should return 1 result with a value of 1" { $Results = Invoke-ExcelQuery $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 500772f..db8ff73 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -2,16 +2,13 @@ $scriptPath = $PSScriptRoot Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force $tfp = "$scriptPath\Read-OleDbData.xlsx" -$ACEnotWorking = $false $cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" -try { - $Results = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" -} -catch { - $ACEnotWorking = $true +$IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") +if($IsMissingACE){ + Write-Host "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped. Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" } Describe "Read-OleDbData" -Tag "Read-OleDbData" { - $PSDefaultParameterValues = @{ 'It:Skip' = $ACEnotWorking } + $PSDefaultParameterValues = @{ 'It:Skip' = $IsMissingACE } Context "Basic Tests" { It "should be able to open spreadsheet" { $null = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" From 5ec299ff2d5b546c77407a81cb5f4c3d613dcb3d Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 15:43:36 -0500 Subject: [PATCH 019/140] some debugging messages for troubleshooting CI --- __tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index db8ff73..70e9a8b 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -7,6 +7,10 @@ $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetEle if($IsMissingACE){ Write-Host "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped. Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" } +write-host "`$tfp = '$tfp'" +write-host "`Test-Path $tfp = '$(Test-Path $tfp)'" +write-host "`$cs = '$cs'" +write-host "`$IsMissingACE = '$IsMissingACE'" Describe "Read-OleDbData" -Tag "Read-OleDbData" { $PSDefaultParameterValues = @{ 'It:Skip' = $IsMissingACE } Context "Basic Tests" { From 1e522c562b89a9a16be974718d2c2042a14bfb5c Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 16:00:06 -0500 Subject: [PATCH 020/140] test skips for linux/macos, switch to warnings --- .../Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 | 8 ++++++-- .../Read-OleDbDataTests/Read-OleDbData.Tests.ps1 | 13 +++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 index 4f428e2..314f154 100644 --- a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 @@ -4,10 +4,14 @@ Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force $tfp = "$scriptPath\Read-OleDbData.xlsx" $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") if($IsMissingACE){ - Write-Host "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped. Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" + Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped. Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" } +Write-Warning "`$tfp = '$tfp'" +Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" +Write-Warning "`$IsMissingACE = '$IsMissingACE'" +$skip = $IsLinux -or $IsMacOS -or $IsMissingACE Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" { - $PSDefaultParameterValues = @{ 'It:Skip' = $IsMissingACE } + $PSDefaultParameterValues = @{ 'It:Skip' = $skip } Context "Sheet1`$A1" { It "Should return 1 result with a value of 1" { $Results = Invoke-ExcelQuery $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 70e9a8b..3697b35 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -5,14 +5,15 @@ $tfp = "$scriptPath\Read-OleDbData.xlsx" $cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") if($IsMissingACE){ - Write-Host "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped. Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" + Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped. Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" } -write-host "`$tfp = '$tfp'" -write-host "`Test-Path $tfp = '$(Test-Path $tfp)'" -write-host "`$cs = '$cs'" -write-host "`$IsMissingACE = '$IsMissingACE'" +Write-Warning "`$tfp = '$tfp'" +Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" +Write-Warning "`$cs = '$cs'" +Write-Warning "`$IsMissingACE = '$IsMissingACE'" +$skip = $IsLinux -or $IsMacOS -or $IsMissingACE Describe "Read-OleDbData" -Tag "Read-OleDbData" { - $PSDefaultParameterValues = @{ 'It:Skip' = $IsMissingACE } + $PSDefaultParameterValues = @{ 'It:Skip' = $skip } Context "Basic Tests" { It "should be able to open spreadsheet" { $null = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" From a3dced10e4ecc15bc3ff5b19e820927668380b13 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 16:37:00 -0500 Subject: [PATCH 021/140] update tests --- .../Invoke-ExcelQuery.Tests.ps1 | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 index 314f154..8c62e95 100644 --- a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 @@ -2,16 +2,37 @@ $scriptPath = $PSScriptRoot Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force $tfp = "$scriptPath\Read-OleDbData.xlsx" -$IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") -if($IsMissingACE){ - Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped. Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" +$skip = $IsLinux -or $IsMacOS #init default, not supported on mac or linux +try { + $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") + if ($IsMissingACE) { + Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped." + } + $skip = $skip -or $IsMissingACE } +catch { + Write-Warning "Unable to get sources from System.Data.OleDb. Tests will be skipped." + $skip = $true #this will fail if the call to get the sources fails, usually means System.Data.OleDb isn't installed/supported +} + + Write-Warning "`$tfp = '$tfp'" Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" Write-Warning "`$IsMissingACE = '$IsMissingACE'" -$skip = $IsLinux -or $IsMacOS -or $IsMissingACE + Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" { $PSDefaultParameterValues = @{ 'It:Skip' = $skip } + Context "Basic Checks" { + It "Should have a valid Test file" { + Test-Path $tfp | Should -Be $true + } + It "Should have the Read-OleDbData command loaded" { + (Get-Command Read-OleDbData) -ne $null | Should -Be $true + } + It "Should have the Invoke-ExcelQuery command loaded" { + (Get-Command Invoke-ExcelQuery) -ne $null | Should -Be $true + } + } Context "Sheet1`$A1" { It "Should return 1 result with a value of 1" { $Results = Invoke-ExcelQuery $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" From ebe49f1650d8b18cc16a41adb2d28815849c8e27 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 16:56:23 -0500 Subject: [PATCH 022/140] fix or/and --- __tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 | 2 +- __tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 index 8c62e95..6bf6951 100644 --- a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 @@ -8,7 +8,7 @@ try { if ($IsMissingACE) { Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped." } - $skip = $skip -or $IsMissingACE + $skip = $skip -and $IsMissingACE } catch { Write-Warning "Unable to get sources from System.Data.OleDb. Tests will be skipped." diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 3697b35..6611a4d 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -11,7 +11,7 @@ Write-Warning "`$tfp = '$tfp'" Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" Write-Warning "`$cs = '$cs'" Write-Warning "`$IsMissingACE = '$IsMissingACE'" -$skip = $IsLinux -or $IsMacOS -or $IsMissingACE +$skip = ($IsLinux -or $IsMacOS) -and $IsMissingACE Describe "Read-OleDbData" -Tag "Read-OleDbData" { $PSDefaultParameterValues = @{ 'It:Skip' = $skip } Context "Basic Tests" { From d41fbf8a05da0a03c049ead66a9e801fa9afb3bb Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 17:13:40 -0500 Subject: [PATCH 023/140] updating tests --- .../Invoke-ExcelQuery.Tests.ps1 | 78 +++++++++---------- .../Read-OleDbData.Tests.ps1 | 42 ++++++---- 2 files changed, 67 insertions(+), 53 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 index 6bf6951..2b02de9 100644 --- a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 @@ -1,42 +1,42 @@ -#Requires -Modules Pester -$scriptPath = $PSScriptRoot -Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force -$tfp = "$scriptPath\Read-OleDbData.xlsx" -$skip = $IsLinux -or $IsMacOS #init default, not supported on mac or linux -try { - $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") - if ($IsMissingACE) { - Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped." - } - $skip = $skip -and $IsMissingACE -} -catch { - Write-Warning "Unable to get sources from System.Data.OleDb. Tests will be skipped." - $skip = $true #this will fail if the call to get the sources fails, usually means System.Data.OleDb isn't installed/supported -} +# #Requires -Modules Pester +# $scriptPath = $PSScriptRoot +# Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force +# $tfp = "$scriptPath\Read-OleDbData.xlsx" +# $skip = $IsLinux -or $IsMacOS #init default, not supported on mac or linux +# try { +# $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") +# if ($IsMissingACE) { +# Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped." +# } +# $skip = $skip -and $IsMissingACE +# } +# catch { +# Write-Warning "Unable to get sources from System.Data.OleDb. Tests will be skipped." +# $skip = $true #this will fail if the call to get the sources fails, usually means System.Data.OleDb isn't installed/supported +# } -Write-Warning "`$tfp = '$tfp'" -Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" -Write-Warning "`$IsMissingACE = '$IsMissingACE'" +# Write-Warning "`$tfp = '$tfp'" +# Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" +# Write-Warning "`$IsMissingACE = '$IsMissingACE'" -Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" { - $PSDefaultParameterValues = @{ 'It:Skip' = $skip } - Context "Basic Checks" { - It "Should have a valid Test file" { - Test-Path $tfp | Should -Be $true - } - It "Should have the Read-OleDbData command loaded" { - (Get-Command Read-OleDbData) -ne $null | Should -Be $true - } - It "Should have the Invoke-ExcelQuery command loaded" { - (Get-Command Invoke-ExcelQuery) -ne $null | Should -Be $true - } - } - Context "Sheet1`$A1" { - It "Should return 1 result with a value of 1" { - $Results = Invoke-ExcelQuery $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" - @($Results).length + $Results.A1 | Should -Be 2 - } - } -} +# Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" { +# $PSDefaultParameterValues = @{ 'It:Skip' = $skip } +# Context "Basic Checks" { +# It "Should have a valid Test file" { +# Test-Path $tfp | Should -Be $true +# } +# It "Should have the Read-OleDbData command loaded" { +# (Get-Command Read-OleDbData) -ne $null | Should -Be $true +# } +# It "Should have the Invoke-ExcelQuery command loaded" { +# (Get-Command Invoke-ExcelQuery) -ne $null | Should -Be $true +# } +# } +# Context "Sheet1`$A1" { +# It "Should return 1 result with a value of 1" { +# $Results = Invoke-ExcelQuery $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" +# @($Results).length + $Results.A1 | Should -Be 2 +# } +# } +# } diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 6611a4d..9302801 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -1,25 +1,39 @@ #Requires -Modules Pester -$scriptPath = $PSScriptRoot -Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force -$tfp = "$scriptPath\Read-OleDbData.xlsx" -$cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" -$IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") -if($IsMissingACE){ - Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped. Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" +Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force +$skip = $true +try { + $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") + if ($IsMissingACE) { + Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped." + } + $skip = $IsMissingACE } -Write-Warning "`$tfp = '$tfp'" -Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" -Write-Warning "`$cs = '$cs'" -Write-Warning "`$IsMissingACE = '$IsMissingACE'" -$skip = ($IsLinux -or $IsMacOS) -and $IsMissingACE +catch { + Write-Warning "Unable to get sources from System.Data.OleDb. Tests will be skipped." +} + Describe "Read-OleDbData" -Tag "Read-OleDbData" { $PSDefaultParameterValues = @{ 'It:Skip' = $skip } + BeforeAll{ + $scriptPath = $PSScriptRoot + $tfp = "$scriptPath\Read-OleDbData.xlsx" + $cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" + Write-Warning "`$tfp = '$tfp'" + Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" + Write-Warning "`$cs = '$cs'" + } Context "Basic Tests" { - It "should be able to open spreadsheet" { + It "Should have a valid Test file" { + Test-Path $tfp | Should -Be $true + } + It "Should have the Read-OleDbData command loaded" { + (Get-Command Read-OleDbData) -ne $null | Should -Be $true + } + It "Should be able to open spreadsheet" { $null = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" $true | Should -Be $true } - It "should return PSCustomObject for single result" { + It "Should return PSCustomObject for single result" { #multiple records will come back as Object[], but not going to test for that $Results = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" $Results.GetType().Name | Should -Be 'PSCustomObject' From 5f00f5cbbc40993f20835f08be6227748a9caf00 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 17:40:33 -0500 Subject: [PATCH 024/140] update tests --- .../Read-OleDbData.Tests.ps1 | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 9302801..8031ba8 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -1,33 +1,43 @@ #Requires -Modules Pester -Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force -$skip = $true +if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) { + Import-Module $PSScriptRoot\..\ImportExcel.psd1 +} + +$skip = $false +if ($IsLinux -or $IsMacOS) { + $skip = $true + Write-Warning "Read-OleDbData: Linux and MacOs are not supported. Skipping tests." +} try { - $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") - if ($IsMissingACE) { - Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped." + if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") { + $skip = $true + Write-Warning "Read-OleDbData: Microsoft.ACE.OLEDB.12.0 provider not found. Skipping tests." } $skip = $IsMissingACE } catch { - Write-Warning "Unable to get sources from System.Data.OleDb. Tests will be skipped." + $skip = $true + Write-Warning "Read-OleDbData: Calls to System.Data.OleDb failed. Skipping tests." } Describe "Read-OleDbData" -Tag "Read-OleDbData" { $PSDefaultParameterValues = @{ 'It:Skip' = $skip } - BeforeAll{ + BeforeAll { $scriptPath = $PSScriptRoot $tfp = "$scriptPath\Read-OleDbData.xlsx" $cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" - Write-Warning "`$tfp = '$tfp'" - Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" - Write-Warning "`$cs = '$cs'" + if (!$skip) { + Write-Warning "`$tfp = '$tfp'" + Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" + Write-Warning "`$cs = '$cs'" + } } Context "Basic Tests" { It "Should have a valid Test file" { Test-Path $tfp | Should -Be $true } It "Should have the Read-OleDbData command loaded" { - (Get-Command Read-OleDbData) -ne $null | Should -Be $true + (Get-Command Read-OleDbData -ErrorAction SilentlyContinue) -ne $null | Should -Be $true } It "Should be able to open spreadsheet" { $null = Read-OleDbData -ConnectionString $cs -SqlStatement "select 1" From f0b4cb28f612855335cacb63c877fc4e8076c525 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 17:44:03 -0500 Subject: [PATCH 025/140] update tests to skip other pre-checks if linux/mac --- .../Read-OleDbData.Tests.ps1 | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 8031ba8..8b7f07d 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -7,17 +7,18 @@ $skip = $false if ($IsLinux -or $IsMacOS) { $skip = $true Write-Warning "Read-OleDbData: Linux and MacOs are not supported. Skipping tests." -} -try { - if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") { - $skip = $true - Write-Warning "Read-OleDbData: Microsoft.ACE.OLEDB.12.0 provider not found. Skipping tests." +}else{ + try { + if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") { + $skip = $true + Write-Warning "Read-OleDbData: Microsoft.ACE.OLEDB.12.0 provider not found. Skipping tests." + } + $skip = $IsMissingACE + } + catch { + $skip = $true + Write-Warning "Read-OleDbData: Calls to System.Data.OleDb failed. Skipping tests." } - $skip = $IsMissingACE -} -catch { - $skip = $true - Write-Warning "Read-OleDbData: Calls to System.Data.OleDb failed. Skipping tests." } Describe "Read-OleDbData" -Tag "Read-OleDbData" { From 9daefc2925b12e64a4b7b65eafca5d4dbf712555 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 17:45:33 -0500 Subject: [PATCH 026/140] fix typo in skip logic --- __tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 8b7f07d..8ad8ff5 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -13,7 +13,6 @@ if ($IsLinux -or $IsMacOS) { $skip = $true Write-Warning "Read-OleDbData: Microsoft.ACE.OLEDB.12.0 provider not found. Skipping tests." } - $skip = $IsMissingACE } catch { $skip = $true From 9ba20b8ec8245ce440c2de7ce884f223b2b11736 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 17:57:44 -0500 Subject: [PATCH 027/140] add back invoke tests, sync skip methods --- .../Invoke-ExcelQuery.Tests.ps1 | 84 ++++++++++--------- .../Read-OleDbData.Tests.ps1 | 6 -- 2 files changed, 44 insertions(+), 46 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 index 2b02de9..89405d8 100644 --- a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 @@ -1,42 +1,46 @@ -# #Requires -Modules Pester -# $scriptPath = $PSScriptRoot -# Import-Module $scriptPath\..\..\ImportExcel.psd1 -Force -# $tfp = "$scriptPath\Read-OleDbData.xlsx" -# $skip = $IsLinux -or $IsMacOS #init default, not supported on mac or linux -# try { -# $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") -# if ($IsMissingACE) { -# Write-Warning "MICROSOFT.ACE.OLEDB is missing! Tests will be skipped." -# } -# $skip = $skip -and $IsMissingACE -# } -# catch { -# Write-Warning "Unable to get sources from System.Data.OleDb. Tests will be skipped." -# $skip = $true #this will fail if the call to get the sources fails, usually means System.Data.OleDb isn't installed/supported -# } +#Requires -Modules Pester +if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) { + Import-Module $PSScriptRoot\..\ImportExcel.psd1 +} + +$skip = $false +if ($IsLinux -or $IsMacOS) { + $skip = $true + Write-Warning "Read-OleDbData: Linux and MacOs are not supported. Skipping tests." +}else{ + try { + if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") { + $skip = $true + Write-Warning "Read-OleDbData: Microsoft.ACE.OLEDB.12.0 provider not found. Skipping tests." + } + } + catch { + $skip = $true + Write-Warning "Read-OleDbData: Calls to System.Data.OleDb failed. Skipping tests." + } +} -# Write-Warning "`$tfp = '$tfp'" -# Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" -# Write-Warning "`$IsMissingACE = '$IsMissingACE'" - -# Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" { -# $PSDefaultParameterValues = @{ 'It:Skip' = $skip } -# Context "Basic Checks" { -# It "Should have a valid Test file" { -# Test-Path $tfp | Should -Be $true -# } -# It "Should have the Read-OleDbData command loaded" { -# (Get-Command Read-OleDbData) -ne $null | Should -Be $true -# } -# It "Should have the Invoke-ExcelQuery command loaded" { -# (Get-Command Invoke-ExcelQuery) -ne $null | Should -Be $true -# } -# } -# Context "Sheet1`$A1" { -# It "Should return 1 result with a value of 1" { -# $Results = Invoke-ExcelQuery $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" -# @($Results).length + $Results.A1 | Should -Be 2 -# } -# } -# } +Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" { + $PSDefaultParameterValues = @{ 'It:Skip' = $skip } + BeforeAll { + $tfp = "$PSScriptRoot\Read-OleDbData.xlsx" + } + Context "Basic Checks" { + It "Should have a valid Test file" { + Test-Path $tfp | Should -Be $true + } + It "Should have the Read-OleDbData command loaded" { + (Get-Command Read-OleDbData) -ne $null | Should -Be $true + } + It "Should have the Invoke-ExcelQuery command loaded" { + (Get-Command Invoke-ExcelQuery) -ne $null | Should -Be $true + } + } + Context "Sheet1`$A1" { + It "Should return 1 result with a value of 1" { + $Results = Invoke-ExcelQuery $tfp "select ROUND(F1) as [A1] from [sheet1`$A1:A1]" + @($Results).length + $Results.A1 | Should -Be 2 + } + } +} diff --git a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 index 8ad8ff5..7a9ef5c 100644 --- a/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Read-OleDbData.Tests.ps1 @@ -19,18 +19,12 @@ if ($IsLinux -or $IsMacOS) { Write-Warning "Read-OleDbData: Calls to System.Data.OleDb failed. Skipping tests." } } - Describe "Read-OleDbData" -Tag "Read-OleDbData" { $PSDefaultParameterValues = @{ 'It:Skip' = $skip } BeforeAll { $scriptPath = $PSScriptRoot $tfp = "$scriptPath\Read-OleDbData.xlsx" $cs = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$tfp;Extended Properties='Excel 12.0 Xml;HDR=NO;IMEX=1;'" - if (!$skip) { - Write-Warning "`$tfp = '$tfp'" - Write-Warning "`Test-Path $tfp = '$(Test-Path $tfp)'" - Write-Warning "`$cs = '$cs'" - } } Context "Basic Tests" { It "Should have a valid Test file" { From ae31e9d39bd5ae6545f19c0e6c7b65d9fc64723a Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 18:08:45 -0500 Subject: [PATCH 028/140] update skip/help msgs in invoke cmd --- Public/Invoke-ExcelQuery.ps1 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Public/Invoke-ExcelQuery.ps1 b/Public/Invoke-ExcelQuery.ps1 index 3b8817e..4cb01a9 100644 --- a/Public/Invoke-ExcelQuery.ps1 +++ b/Public/Invoke-ExcelQuery.ps1 @@ -45,9 +45,14 @@ function Invoke-ExcelQuery { [String] $Query # var name consistent with Invoke-Sqlcmd ) - $IsMissingACE = $null -eq ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -like "Microsoft.ACE.OLEDB*") - if($IsMissingACE){ - Write-Error "MICROSOFT.ACE.OLEDB is missing! Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920" + try { + if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") { + Write-Error "Microsoft.ACE.OLEDB.12.0 provider is missing! Please install from https://www.microsoft.com/en-us/download/details.aspx?id=54920" + return + } + } + catch { + Write-Error "System.Data.OleDb is not working or you are on an unsupported platform." return } From 487cf51abc372a4223f3a0656eb5d86c82c515dc Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 18:19:23 -0500 Subject: [PATCH 029/140] fix test skip label name --- __tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 index 89405d8..46e964d 100644 --- a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 @@ -6,17 +6,17 @@ if (-not (Get-command Import-Excel -ErrorAction SilentlyContinue)) { $skip = $false if ($IsLinux -or $IsMacOS) { $skip = $true - Write-Warning "Read-OleDbData: Linux and MacOs are not supported. Skipping tests." + Write-Warning "Invoke-ExcelQuery: Linux and MacOs are not supported. Skipping tests." }else{ try { if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") { $skip = $true - Write-Warning "Read-OleDbData: Microsoft.ACE.OLEDB.12.0 provider not found. Skipping tests." + Write-Warning "Invoke-ExcelQuery: Microsoft.ACE.OLEDB.12.0 provider not found. Skipping tests." } } catch { $skip = $true - Write-Warning "Read-OleDbData: Calls to System.Data.OleDb failed. Skipping tests." + Write-Warning "Invoke-ExcelQuery: Calls to System.Data.OleDb failed. Skipping tests." } } From 7177623104c63aaf6bdf2bda0416b97e746d5b2c Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Mon, 8 Nov 2021 18:21:11 -0500 Subject: [PATCH 030/140] add silent continue to cmd check tests --- __tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 index 46e964d..e79f96d 100644 --- a/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 +++ b/__tests__/Read-OleDbDataTests/Invoke-ExcelQuery.Tests.ps1 @@ -31,10 +31,10 @@ Describe "Invoke-ExcelQuery" -Tag "Invoke-ExcelQuery" { Test-Path $tfp | Should -Be $true } It "Should have the Read-OleDbData command loaded" { - (Get-Command Read-OleDbData) -ne $null | Should -Be $true + (Get-Command Read-OleDbData -ErrorAction SilentlyContinue) -ne $null | Should -Be $true } It "Should have the Invoke-ExcelQuery command loaded" { - (Get-Command Invoke-ExcelQuery) -ne $null | Should -Be $true + (Get-Command Invoke-ExcelQuery -ErrorAction SilentlyContinue) -ne $null | Should -Be $true } } Context "Sheet1`$A1" { From 4fa6fbda012feb2d830ae19a9ed4c674babe8c03 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 9 Nov 2021 09:05:15 -0500 Subject: [PATCH 031/140] update warning msg for Read-OleDbData --- Public/Read-OleDbData.ps1 | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/Public/Read-OleDbData.ps1 b/Public/Read-OleDbData.ps1 index ccd0fdc..491b54c 100644 --- a/Public/Read-OleDbData.ps1 +++ b/Public/Read-OleDbData.ps1 @@ -36,28 +36,15 @@ function Read-OleDbData { [String] $SqlStatement ) - if ($IsLinux -or $IsMacOS) { - #todo: possibly add support for linux/mac somehow. i haven't researched this at all as i - # don't have a need for that and i'm not sure anyone else would in this context, but it does - # appear that once upon a time mono had support for oledb, so maybe it is (or was) supported. - # mono link here: https://www.mono-project.com/archived/ole_db/ - Write-Error "Read-OleDbData only runs on Windows" + try { + if ((New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME -notcontains "Microsoft.ACE.OLEDB.12.0") { + Write-Warning "Microsoft.ACE.OLEDB.12.0 provider is missing! You will not be able to query Excel files without it. Please install from https://www.microsoft.com/en-us/download/details.aspx?id=54920" + } + } + catch { + Write-Error "System.Data.OleDb is not working or you are on an unsupported platform." return } - - #todo: add checks for dotnet libs - #todo: possibly add checks for ace drivers, but maybe only needed if we want to restrict usage. - # i currently just pass through the query and connection string so user is only limited by - # their own machine setup, but they have to check for those dependencies themselves. - #todo: possibly try/catch. i personally do not do this, as i let them throw naturally and catch - # them/handle them outside of this function. - #todo: possibly allow for DataSets instead of just DataTable. I used to use a similar method before - # switching to the sqlcmd module and use datasets as I had multiple tables coming back from - # sql sometimes. i think in this case, it's best to just keep it simple, but maybe someone - # out there would prefer to be able to get multiple tables back. i have not tested that - # with the OleDbDataAdapter. - #todo: possibly just return the datatable, i do it as below because i prefer to simplify the output - # and get rid of the extra fields that come back with the datatable or rows. $DataTable = new-object System.Data.DataTable $DataAdapter = new-object System.Data.OleDb.OleDbDataAdapter $SqlStatement, $ConnectionString From 8f0fc7397dc209b1ea97fd945d66083177a226f3 Mon Sep 17 00:00:00 2001 From: muschebubusche <65829739+muschebubusche@users.noreply.github.com> Date: Sun, 7 Nov 2021 22:52:54 +0100 Subject: [PATCH 032/140] Add example and automatic column arrangement Add example and automatic column arrangement --- Examples/ImportColumns/ImportColumns.ps1 | 9 +++++++++ Public/Import-Excel.ps1 | 21 +++++++++++++++++++++ __tests__/ImportExcelHeaderName.tests.ps1 | 14 ++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 Examples/ImportColumns/ImportColumns.ps1 diff --git a/Examples/ImportColumns/ImportColumns.ps1 b/Examples/ImportColumns/ImportColumns.ps1 new file mode 100644 index 0000000..c022b8a --- /dev/null +++ b/Examples/ImportColumns/ImportColumns.ps1 @@ -0,0 +1,9 @@ +try {Import-Module $PSScriptRoot\..\..\ImportExcel.psd1} catch {throw ; return} + +# Create example file +$xlFile = "$PSScriptRoot\ImportColumns.xlsx" +Get-Process | Export-Excel -Path $xlFile +# -ImportColumns will also arrange columns +Import-Excel -Path $xlFile -ImportColumns @(1,3,2) -NoHeader -StartRow 1 +# Get only pm, npm, cpu, id, processname +Import-Excel -Path $xlFile -ImportColumns @(6,7,12,25,46) | Format-Table -AutoSize \ No newline at end of file diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index 6e4b3bf..d71792b 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -163,6 +163,17 @@ } else { if ($ImportColumns) { + # Safe the original array because $ImportColumns needs to be sorted for calculation + $tempArray = $ImportColumns + $ImportColumns = $ImportColumns | Sort-Object + # Check order + if (($tempArray[0] -ne $ImportColumns[0]) -or ($tempArray[$tempArray.Count - 1] -ne $ImportColumns[$ImportColumns.Count - 1])) { + $arrange = $true + } else { + for ($i = 0; $i -lt $ImportColumns.Count; $i++) { + if ($ImportColumns[$i] -ne $tempArray[$i]) { $arrange = $true;break } + } + } $end = $Worksheet.Dimension.End.Column if (($StartColumn -ne 1) -or ($EndColumn -ne $end)) { Write-Warning -Message "If ImportColumns is set than individual StartColumn and EndColumn will be ignored." } # Variable to store all removed columns @@ -192,6 +203,16 @@ } $ExcelPackage = Clear-ExcelPackage -Start $start -Count $count } + # Arrange columns accordingly to $ImportColumns + if ($arrange) { + for ($i = 0; $i -lt $ImportColumns.Count; $i++) { + $srcCol = [array]::IndexOf($ImportColumns,$tempArray[$i]) + 1 + $destCol = $ImportColumns.Count + ($i + 1) + $Worksheet.Cells[1,$srcCol,$EndRow,$srcCol].Copy(($Worksheet.Cells[1,$destCol,$EndRow,$destCol])) + } + $ExcelPackage = Clear-ExcelPackage -Start 1 -Count $ImportColumns.Count + Remove-Variable -Name 'tempArray' + } # Create new array out of the $ImportColumns.Count for the further processing $columns = 1..$ImportColumns.Count } diff --git a/__tests__/ImportExcelHeaderName.tests.ps1 b/__tests__/ImportExcelHeaderName.tests.ps1 index 85ae5a5..9ee4e4b 100644 --- a/__tests__/ImportExcelHeaderName.tests.ps1 +++ b/__tests__/ImportExcelHeaderName.tests.ps1 @@ -364,4 +364,18 @@ Describe "Import-Excel on a sheet with no headings" { $actual[0].E | Should -Be '5' } + + It "Should arrange the columns if -ImportColumns is not in order" { + $actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(5,1,4)) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 3 + $actualNames[0] | Should -Be 'E' + $actualNames[1] | Should -Be 'A' + $actualNames[2] | Should -Be 'D' + + $actual[0].E | Should -Be '5' + $actual[0].A | Should -Be '1' + $actual[0].D | Should -Be '4' + } } \ No newline at end of file From 1ee9493bc005702f8f983e120d838b4e9df4cd9e Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 12 Nov 2021 17:25:45 -0500 Subject: [PATCH 033/140] Minor tweak. Display query executed --- Examples/InvokeExcelQuery/Examples.ps1 | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Examples/InvokeExcelQuery/Examples.ps1 b/Examples/InvokeExcelQuery/Examples.ps1 index c565292..a42da76 100644 --- a/Examples/InvokeExcelQuery/Examples.ps1 +++ b/Examples/InvokeExcelQuery/Examples.ps1 @@ -1,13 +1,14 @@ -try {Import-Module $PSScriptRoot\..\..\ImportExcel.psd1} catch {throw ; return} +try { Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 } catch { throw ; return } $queries = - 'select * from [sheet1$A:A]', - 'select * from [sheet1$]', - 'select * from [sheet1$A2:E11]', - 'select F2,F5 from [sheet1$A2:E11]', - 'select * from [sheet1$A2:E11] where F2 = "Grocery"', - 'select F2 as [Category], F5 as [Discount], F5*2 as [DiscountPlus] from [sheet1$A2:E11]' +'select * from [sheet1$A:A]', +'select * from [sheet1$]', +'select * from [sheet1$A2:E11]', +'select F2,F5 from [sheet1$A2:E11]', +'select * from [sheet1$A2:E11] where F2 = "Grocery"', +'select F2 as [Category], F5 as [Discount], F5*2 as [DiscountPlus] from [sheet1$A2:E11]' foreach ($query in $queries) { - Invoke-ExcelQuery .\testOleDb.xlsx $query| Format-Table + "query: $($query)" + Invoke-ExcelQuery .\testOleDb.xlsx $query | Format-Table } From 4e89b3321acb66dc3f09916410ab97909d9c8b57 Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 12 Nov 2021 19:23:31 -0500 Subject: [PATCH 034/140] update change log --- changelog.md | 38 +++++++++++++++++++++++++++++++++++++ images/SQL-Spreadsheet.png | Bin 0 -> 12058 bytes 2 files changed, 38 insertions(+) create mode 100644 images/SQL-Spreadsheet.png diff --git a/changelog.md b/changelog.md index bf200b8..7507581 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,41 @@ +# v7.3.1 + +- Added query Excel spreadsheets, with SQL queries! + +```powershell +$query = 'select F2 as [Category], F5 as [Discount], F5*2 as [DiscountPlus] from [sheet1$A2:E11]' + +Invoke-ExcelQuery .\testOleDb.xlsx $query +``` + +![](./images/SQL-Spreadsheet.png) + +## Result + +``` +Category Discount DiscountPlus +-------- -------- ------------ +Cosmetics 0.7 1.4 +Grocery 0.3 0.6 +Apparels 0.2 0.4 +Electronics 0.1 0.2 +Electronics 0 0 +Apparels 0.8 1.6 +Electronics 0.7 1.4 +Cosmetics 0.6 1.2 +Grocery 0.4 0.8 +Grocery 0.3 0.6 +``` + +- Thank you to Roy Ashbrook for the SQL query code. Catch up with Roy: + +|Media|Link| +|---|---| +|twitter|https://twitter.com/royashbrook +|github|https://github.com/royashbrook +|linkedin|https://linkedin.com/in/royashbrook +|blog|https://ashbrook.io + # v7.3.0 - Fix throwing error when a Worksheet name collides with a method, or property name on the `OfficeOpenXml.ExcelPackage` package diff --git a/images/SQL-Spreadsheet.png b/images/SQL-Spreadsheet.png new file mode 100644 index 0000000000000000000000000000000000000000..5c26cdc166dcdcdd532491d1f4b9c07c94a6617d GIT binary patch literal 12058 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 Az5oCK literal 0 HcmV?d00001 From fe4f2848adcf3ad5c75218b73190058f425cf794 Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 12 Nov 2021 19:23:36 -0500 Subject: [PATCH 035/140] bump version --- ImportExcel.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index 8143435..b190043 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.3.0' + ModuleVersion = '7.3.1' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' From 5cd3897dfa575f0c6b607dfb1d55c42c2d477995 Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 12 Nov 2021 19:26:57 -0500 Subject: [PATCH 036/140] fix png --- images/SQL-Spreadsheet.png | Bin 12058 -> 11715 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/SQL-Spreadsheet.png b/images/SQL-Spreadsheet.png index 5c26cdc166dcdcdd532491d1f4b9c07c94a6617d..fe493e603fd35f934069f48aceb8d4c87bad8dd3 100644 GIT binary patch literal 11715 zcmcJVbyU<}_wP|qI;5mg7(#Lo$$=rHyOov@P^23MkPd;7ZiZ4&2>~Ufa}baa38?{w zt^sD~x`W^6K5@VIS--XJTK5lPF(1yHIcLXvzxIyN(NZQQVj#l7!68*uQP9J|xuJpm z{e<8)_PYiP2|xA+p{t6q2M!Kd*Y($pR9-Sh>>u$xRW%jymx)Pn=$T%xNMRSahoh<> zXW*N&om=IyI5`y+Y_=Wz*)ny7$Am84U0+Y`u4WYlhgvGpgE2a%h-_7w2eBzHe`dVA z^+BnyFxHM*s+)&-hLb~#fi$jgT4(lx%KL&w^mq~s2E!+xWgjIL&VCoFMR<@^ZsYpF zep*+3eoJw6hPc`dzB&q4-4@WNmZ$|hke8vkf7_7TPU13giSYbj!cukT|9pkpN=YdXM1VW|q zLj89@R+rdUj#0r^jfaFw5p3`@fZ|#STUS0&H=lA@_;>X*H|=`@+UWt4)6<>Hqjm}D zxr7I?XZj%Tqg6`AjYt)}?UIRroN71N98x5r^Obj*AF`pruh|xj&SpJY4`g8Pvu7t1 z<}>b*4)K***vyYL`V`wf@nfKD3!ss`@q_M7_suumbYf#SOtOQbBHo(FNSj+%Uf$wD zMo=ByL?#Qa74P1j?s?jXY-qC{?#NHQSW3hz4*}(2{||;hxok~-;L^~ojtjV1<$D?{ zcYxP=;T^g$zp1oSQJn@fKiu0XCW4$L_RXg8tYb#01Wa+i+=jKczzz|?TFa!h2UXzH z=A1g`@I=<|{hj@-tKo0^}?Gw{o|%ezaGfX|bk&rs$bQ~yS{h0g? zj-E;e&-aHrgr!z8L5n902g`;Zg5vF^km`N(!lN#QMV2ES!gh+98I8xjrx= zUcBIe0bByhEKzP#4Eg@(>7JeXS{5{IG!=Dcu<`TJleZN-$c~~GTblzt$l`) zv8f7a69bL^rW^V(gxZGZs&t%V&3z9&B;&G$w=e%6P7?N!M)iO2qaqB}QKnBfD_eJu z5Wz@P>s8PGRp%w+m=Xn^u7R4WWMB*A8F+FONlRQ-SxzY%<^$*;5_zH;bNLTW&S#GZ zI&j6TTIOJ!s}mVMx`L@X)Kdl!>K0fht?E)h^;03#oa2E_a?nev(w<0JtWPy(VOo0$i&E)ApC%eOo#N1 zHScsEHm9?rJYIk1SyawNKt<@_rotJ?7TX4$RfdDu*|3t0XU1>6oj4(j%MKr9>(;6* zkBT*_d<16J>CK|tyjHn^H7afFw2--ewAK66qfK(jkvHs{UMVs{) zhu>p!zRXZMux|pJrenr|t57K&5_K?xoDH2CG?>pN(1+l+_}-AY`g#xhn~Xok4SIp zIE{vW4qh=gTZ__y(DL=C&x~7LGV5#qwC@BdJ3Z_w`V}A~ITwVc#UG@Dej&tws3->L zS2XIUA0@G@_Rv4V?6oz1jz|cJ@s0?D@xvb4t~fo~JL6+{5WMCQEmp89(cV9BkuGYT zG^&l^ppCqw%M&86!!SN;EyP<>v2yI+6`GcpTE+4 z&+o;2nC|1N_Mn^qCawGkgg~WcQC(Bm>s4p{a;U<^X#1qGzQ+0E?!Fr@V_g=3zgD}x zy>iV_w9x^{&X=<|&N;&{ly)biWOpc=PF}aHeKePl<=@9)@Hk^d>S}Dz-H&F`#A$m~ z)B(;Lh&x!!42Gwu()|E?JYVS%>g-o=l?(NV8V!EEZnmyJkiH`Xf<5CyQ1k^-3(YN) z^$fBj3M^E2I_cV_@?^+_KIA^$AQT(Vc?wg2|86iPnN^;o+s$LL9-MYcUSxjn;pKQb zUYVn<<=7Lo3t!%6WGaN39vR^saC%%l1^4*HzkojeB^17ElkKxP)5wTU@DOVUODc2= z2ed0N3dMx_HF;Z1WB6JSg{%ik7A+NpHifwn&~662)6S+ami@^2!$g$Xa!+Gun1Zlw zuaxL?=^B;8lYaQt!#SpohU~{n5Xv6L$N}X0;OycahCfzkCxyN#K;#1btYe5*$you3~$jQ0jE zY}9`>w2xlg+ZjUC#y$B(yJop^?&svTcbF{0iJE+K$_+FsyxbeA62VPkaP*$5zaxaq zH!e!#l;GN$lq%T{;CC5}Uh#-ucgS?3g)*W7H$g29BvL40Z<#_r#xdC5DW8;`L}^nt zV45#j1U0TppJ&qpad=j%UN4%XdIVdv@}0i$2i?zVb=_MWr>5JgmG}TX z4Ft&dM5#W!+%@SjXZOi*o+Y404~`tcn2;0}xKE@Kd0Og%Eg{1yVBw{A%&U>LAJ2aA za;MH9#^OX!0#=I!ad~x)%_QYC107-mg|c9!@50BUs2NE9Z*^@OjtG05u09kH>Kdj z%l5H>7wVOlxP>;mXZlX&T}Cq@`hX=@kc&=`_9-7N9l}7!!MyNTVpPB*IE0t3I@Q^I z3-kNqo9+{R`9u5S_Op@zJH{U$ZpVw!7K-|?yQHELdkh$3g~t7q-w%0&IG6<%Q`d-D z?X<#Ihfr0IPPbY?ax{ot_8We-wN+OP)-#FxU0e&8nC1M;BGbwuki9gAQ$}9k375*G zo2?n}Q}Tkv*HQG6uVlv)%~@}`7f)DSDQ2Dy_sm!B&mPZ@FBq_F-t74B3`QJ|WRQ~= zdNTpEwD;{XJx>a!DpygE3}l0F$m9RO^IyJUpLVN1tG)DKgwJr-z1x7l)s?lR(_F0D zBAH@UEh~@daLwnNayAfUAuGe=_Qp7RN@_X~=Kcwyoy?tWfpZ?1cXynAqS%@iFz{rC z5!b*asB^?0&ds9hPyE1A)wkPwqE)|VuOW9gt&yiy!jt!@`nUM-aET{ugF^H<9Tfe% zLl0HaHP3xb0p3C;HwiF)6^YCfOV(ukEqk8Ea1m#qmO?|Ljlzi<19P0cY_py`;ieHw z^%%{!RUZ*Lp2m5JCw;1U?5vF)wIRm1PfeuAm5oXlk`bIopkcEX!q0JV>L>T;j(qno5zEx3PXueF(BxoRb)Ehu#3Qi2JbLe zn?hy2L2DcE3;*$p)>VO=1=qj>o58&!zm{mRitjyJ>KT>wGVg5ZHN!`hzt_}6hAEAE zvF~SLKVFg~oML6x6sFUE3GC546{Zt88yshV=63yX+{|w}pLhI?xFpW0vO}8Ij3{W=-JJy1k&3n9YmAdy)i?yH<@GF=SlQIyOH35D26T(7Y zMXWM*tH!;e3$xVgr?=Iz;AfPPTpedJDS9bdLcZv03xG>rMW0ED2}LFF+LIMi2ulP4 zes}LbapV4Hk+r7H{x?_YU4MM-H-8@fPw%=`a{uX2|Dop;!~?zMw5^ck0s^iPzLrZ~ zr@bxC@V!G3L{-PZp|2GG2+e$Flk`LQ5c`71q-Cni(_%KUUdh0>gW_kDD^x-DIpDBy zoO1Ke`PdXpmuFM^(Zu3$EB#2j9pk%L^P&+G!x8!$x|P#@8Z$zH(m$IFbGJ0b=U8gu z^*o4d)^!+|07H91k|fFH!y2wJf$uy0~M7=*aU==i?V zZU_@%zs1W6D_Z%Guw%cDse*h9zwJL>ZSpO~`$K|r9ci8;7pCv7|1Fwk0pGG(#5A%g z=qyd4wh*KvQF_uhwAU$wbV3|$`1y#L{ns>=*LhB%RFp?_(kNH18*P~tc;RT% z-avb9+roU{H!-KUf`hr9{d}S0mS+B@E7AGkaJ2hH_=(p&_oH3t7-;nMWmvYsUjmGr zc4>yq+iha%WbdVQlwZJcw++Xwr$lf;k{pRG+Gkp-4(Si~a>3u@J%Ct~mfTF|Co#c= z%t-V_TJ_ZbJ8zFx;4ZGXk2`Qz zwZNl4ckiX9qDsmp{`{F24&SV_v$b=fpj3uF&1E|t5RPGA879GDB5E?ZKk^(og}!VvlgETt>jLR;s8szZM<dwLU*i!j!)N8SJSKd)+P94^);Aq1OS(}Wcl-hhp)kf)(l-udXVd2%gMGRKKeb?$Zo8jST-RP&tg7B_x>98S1RnTfodAN+x8anWf6tl&%pD}uG@JzT5yRmp zo-YCdwNO4q2D)Zf@SoC;{ZweHEIA=eznULeX~9ZsXBOR9VjwCK3830huFNBD8LU+n z9+XEId0pTxh1Fk@Q;}aVJaRJjNqQTBN{?Z|mk^AfT&J2#v)A}yygD*~gCQf_8>se(m}>UX!Uku7i63-8xZ<;`vJ*4{Ij zfvA>dbBE?WLQEe&nVr>39Nos4!&|#C&GK`RAPB?Ty-OgU7e!KcbTa3ZU?*!-Q@{(o zqM7#8ai4P?56?|ajd<3XT7FkOUn4ITvdOEuI zU-k>$(Sp%zWS1c8-unrNX#RqBUBS$rP^6BT*O&4SVFNW2_Lw_%0Rz8< zfezaeN9@ItoffYIZSxBo= zw~O~SY4xqMzf6w1U-TK>&6-^LquQOirfig}qJ;OR`>9Hy1<}g{=jPCKUgGmgVx_OE z$!sZvyniu{VVKgt!43D*;>e5U_Tz0lIa|{I>U!mW=OH>Be|e)F(OXc|z1SE*tCqz} zPvi35lLpAtV5U>dyCP+?oj7E=YJtKO7K5lPicE8)bP$npCB%+Kp{x=a+2s`dposSb z&j-!qZH!zOY#F-6lf1>;P(V}M_b*2TXsAS|9kfIol2QYtg6R8W1tfEH8KjAgl4#5U z^WXezrTCI;9%1#r)!|nj5BpkO>kHAM&JJoevUua}h~yUriz@J01?Up**2jUVF?^=t zDwjk@F4wUyb(Pn=!nWeAn;F>KbehBm|5h4>e8u7i&}%knzG@rWMJ@a|?e;gX%O#$v zt%(fYG~7k2`VOcG(Nkyazhw{y-9t%t}j@X`@Ze06qx)?AKecN;0@Qym=8t>mnomV_&j8- zal$nJd&S}HSZlI-n;qXJv!RcVRa&krl!=vz7s&jN~r6$Yem*i zaTjVq8m2OIZ#M{*!X#_u%u*S}F-TWs^4lh7Vg{6`1ZA${Wm4)-a+miVuvjt^|80+U zi^i(>;CaT6rPNc}*jhWh*|ba+hC|hyG|vUUQ^A~2qL9^h1AZXf*>6jV(40IeUcgzb z_X}mA?H2mT)C(%j1#Q$c-F2hwVuD8`D^^oPabW|s{{$Z_sI|xA01ri!3*7Fu5=+FE zXs@$`)K`*`+!G1N2X51vUw#894%fD(gGbS0Ij&+l0NqvGXUzC-xXjjtvl>dR-@Furh|R?%cQ?dvS$r+72hyQLEo9S1#)OlRpk0{k<6ce^R&)WVKjB zxjARTPq4wyH_*Ev`tzhP`&Vg+K+1^K?L8w1`A1%ZkL_IB{@*FB28-C>101)Yy7#V8 zX5r;B9`fC&{T@Av*u1rp&_2Fks9$e^CoJ`n%4xB_YgzOUXi8n<#s6x!4ieGUmaIsBb#JY)qlZaejfEYn zc`ia+a9TXQ^=o*SGh=Q@1TH0_vF|X-Rhr9M6n8VgpIUWPJyq=I{?#$%3dsDaEMzR}cVswE$T|)3)-#;75ps z>mGydv38(TxS!qm+fgo6K$CQQUVtvB{=lp_c5^-PeoOjGAC;afq-Mq$jlmu%D2+AD zRZ4hMP7CJnt4UhUUgEK?l=RP69qOrqe{BbpV*uM*Cg-vNUnFd<@@U2KAH?hqlwr#d zTXMd`!-2-q8X+*5^q~9Q))M>273t+k)#*IY;w2#>|L=`rZC>}2D?d{m-M-NB&(gVM*-QN0Ka61EFPJcw=zSjq2^$)vQuFZ8w5|FNSH;= z1FR{Ss#Z!e^lnh5SnPNed6H-I9L*|_0(ApFxBhj*X53Vwe{;Yc{wss9W%28IEsn=s zqhl23j`hHyl!d_k-A+_bHJ~ugs+!s?-|2V1O zv%#yzb>NXEI1#P447Q`uhITRObY}yhU`ZC%Bm3c-!>2ULj;uV>1C3sd4iS2aZhzES zd1TPXR4<=5z`CS!x=e?f1X$*cwYzgmeO`zq)`E1NBcV^e{(u!(k}l{{fI(ei`aqADKfxy$?Ny$`R}asPvJe zJS}XEE*(tZY7Ch(n@==L&^K2^Mvc@uzB1ic0!ry$k) zhz+fuzx-+&LpbNaL;!Bs1}V|iqn6O-K$#vt%~u)OGGx+*zqi9V)wI;HOFK8NCN>m$ z%t*IS5Y5W*eE|87bFCRAF|!9`A{Pc!Symq#sCjv=HX>Wx&MJC^-bhJXc|2=oj|2>G zod;dSrM0jJ?f1#mvqttaK|2ZO4IcYY{X?xy{Y$OY2b^PfeO|n=riwFOUJO*KE$nRD zw`-g^!7CDN-`#WbnGyTc!kd6n?jEHA<0t*vl5Cn|q|1*m_hrDJpD73CzL=AP@v+uP zh;M(=p3m^=i3wUohcrGB!4}9LXQgesnC((PDk=;KEMDQx91C=Q&C(%a<5;9l=z9EK z|LKvYFM_7`h#iCJ9Sk{OyL@oWd$v>UKgxgpB*v_74e}6JW}x$P8{xptiy0h%tl>^^ z4_oY*$&F_F0s|Z#rJXf&sJ{zOx)6-xLjg#gTrj|&Y7S{zQ5#uSvYl_lBlk#38->IL zm(BtQMAbA`Ld+T4r}l+Sky{i$)CfO~9_2K4(4CwP&W-U+u=*<8-)Ss-7T~|}=}4Wl z=hcAaOO+R7Z%36W5A?1TJx!CD@%=FBu{`Zq9nP}9I>vIr4F84^#T_#g9!?_Oyg_JD zD2(4L`GXsmFp0Kz?{*{qE$J})Un;79aLD&K4ITuA8F*Chhc-R@uf9c$P65G3%AVcs z2{IfJlrPZEf$T98uhK0QFm%#4&(pU6b7Q!GIg z#8QUp15z;?__}b*jS3JqWbhRR!ZE@Z_XuYy^K)cA9A<4yXaCN&fh|7oYkQvv=MJ6V zkjiFJL(TzOKp>+wQ}=P}x|S;qD#>Bm_ws$5O>KuKdn0z1!037wK-ZdCwCHi&YuAC3 zTay2gO|Wt)=-b#c=s{fKf06~FZuGwSL^I$l7JTDWb7e;)p&#z- zn7y!*-$p6lYbcf3_|S#pq)(1CBd8AL+|L|$VYu={1Zdc#Ug%_Vn*A`L+~t`XuIS*+ zv5VRGBRiW$g+?kU8#gH$y&+FD z9r0$si@vWAR&tCdI~ErLtc@GG&#qdEXI#GRL5>y&^Atb7oEtueDsHT|Z` zF|YYqby;=ABIb@0<0vA<>$uzNU zLqiI4W1H_(ZON#Lwk%$u!TbD)CW4ucyt024+eKR0`>Jp)8nXhPtSbA02_;?|ZK`Wx zzUubsMLJ28(X(znHOv7QIw6m<_hpM#j~&y{d$jt_x(+8Nxq)3;tm#gx9P9CPJN&wt zH}St$Vm=vMAL-b+reDE`%_@?HOoHRoaK-2FjznNaIc41MWZ=bO&Bc-V%yq(rnt#tY zWH0ni#he<2J4PWNB))fVbGsPWeHi18Pe=fQQ8UTTd8sjCyR#k}pXe$U%_*HeZMpP4 z7)%a5de2jS(oAoV0~WxdP}PjH)}~u|_D|ozCuDY)>3z@oou$%-8tZaYYdLi*nBn@1 zwb>3emV1N&o`>75-)#jG8M%{6(KkM);X2GI=1Nb%3mUc7A+j_oX|Iz;mFvqtwmwM5 zHb^sD{t%(M0QcrTNI_7wr zB;Lvo{Biz%%kF}IO{2)f|Bb5L|F4mPUE=TT<=;CN3z**pKb^t&(FP|EEuZge`n%aK z_=SjW@9I7`{@uL8Ph7d=KNw_!W%@4!2K_#(`@UJSuoO`>%G!1?ZpcjE*MRZ13aJVcDT- z;EoFQKDC5NxN|=9{b3pJTLIe}xMa2d){gmDZ3>?SR74Tt`1X{o5!UHRNqYQ!q~lu%lUcKh9Cai3 z{6hFokK_K3*r=KoEM-P>PI)N9*jDHNOXThe@A;<1|X&9*d%8 zyHfM{Y5Q53U0@R+S@37p5Z1w&uf2VeJ}kOt%j=9|PiIiy~0B-Kzv`jhlg8 zozpTNo`RlC2?~QBnkbhss&lh|OOuh&CnUoimCBCH?C4{}>*YZ%y0V@&XsbaBEB%m` zbx;n0pp{9u*c$Y3S>sIRslNHuIU`~o_<4`-A{9k%^&c|XL3 z(t;)S9HIFZPGszq_-97h_qW1N-9j&OGj-AaYD!tR9MaAh{Va7#Jse1*ps<4(U<;Ty zPBEjXd)4DkL&&*Po{&0Qq!XL>;<3Lsk#+bj1Th-yH6wceCf%aurTs)p>A;v*@NnUli>mW~m7dY!W(o3F*m17%Pmd z;{rB?PVsmDF`>e#!*@)We&9H7wEW zICMKCE6s1;i4W_eQ+$;jx%vDITSHniywLbsCXNOrmr4X~rTMry~SP)A~FaW8@b@i1*cUm1>;IP8kdeKG#V(^O&^-?byvW4c}v&4 z+HJmG%(1Kd!}Teu4(W?$}G-87HVpRbEjO4;NZsKiZdj0!HB%e;+Yohg71Rk$zeLF81A?V=VtFYALLfkVl74r>75VTv$i&A?#yQvjCer6{bD2h?}_Sm z3%|0*8{#Vbq4`NWEJIb0ZlhJ`W4{-ZwG`K<6H}}C{UC|ZXfp+yfD?I}O+A9_?}m(W zaX=HTJ0RUqmlzfq;Ya>kCQCGA5oyAL%Y(jO-?IVw4sdrbByoPtN^2P&<5RU^wRKGK zqgRd5J#x?Ex~4f%{@?N9vLW8Cn+?8|!mTyx8KYd%&_tls{@2E~X-o0VTt&8xL{Q&4 zRb<@tC#LG0)yEc^_dh9Uw<1p)*7P2o;W9tz@3UFQ=$%Cp^WQT>~4zlL{3yYqo{A{40Z~vp|gQ1pqiE`Xl zvHN%r{5O{I`T!}zzYaejG1PW-Z=Vpoe=NM<$#(#&Te+2f37A(59 z>CQ${%mUH<5^WMG=geof{0h=(!Dpa^5S3_Iy-@5snrb#^A12pa+@%mzDi1Pl}tez_+0nCGN_0Hsk#8RZ~Q z9%Aa`@M_i|lSeU+Ro8UxBaItRdfX%8;j%;*#@gMOx@uKluX`v_k$&K#lIlM9tILlM zx7_&UIG9H^L*YLk1uxSEb*B~UR^SK=mt~b~kW3p88+pW1Ma|PS)y^2~+-dK5CxyK< z1tzQA6}_B{7o=1h6%_8LfGEF`s8Zo3i!9HC`_BC$HR*=Z8p|iSx{L6{8MDH0Y)&Cs zkkx|Ki+9US@@i+KbAGo``MOL$oknK?c0lt#00_px7bqU9aIp?>MPosCb4B0S%WsqHkvf(C;#qG z0yuQlgAk--V5$WcIu!nSGY~i2F9Coxy+rTR=#?Z=i9o$;!|Poy()erWH;kv^E)$lw zE4b@)@IAr;mT2q{G?|zOJW0de_;%3kbx*|4po+{s$9F)PgOe(q+=M8D*41 z??r3e^FD2wD?(#|-t{2wO(b?Qv|L?h5I|sk_XPi6A@?719j|@|`-JkeEGSkb?rkq`l& z(5T^9;1{X4uB9Ii4rSNP5AOTBl&ruXiJ^LiTExp_6gbojUpByOI5>B3^fc8T1;Mv- zji2#Yw=A@7pf!RLMLKfd2ZoE@V^3j>B6%m|M@QP<^0#m;ma4zECFUUJv|@HzA>zLcU-ulkeT6s|jn5h~&^r4z-c1zNGyi0U z_{RJG+k^A)`?F}&v}3RhvUkGklE8Wm5jWPJ6Uq z!1?+ZLNFkQg-I0yc43Nu?n^u9-~j*MB*(aP7|{b?E0<1ET_n9|+->o@%%bl(on-DA zJ}r8>6LU2exUeYKdX|jYed3T5k?U}oq$<4fVCsV-MVGaMoDS>M)KnYF&>eBx?DC{; zN*a=X3A?Q$*%i`054In+BMN1#1OF8gQ4KepLk3dtBCfpbcb`sI=a0l}zb}abiBGXM zxh1x5SS}-+GG2e`2XJ@6?JXL2ugMo)9FU()G(HK* zxc`uYRBr#!k|XHahaw~s$2+>nmuz{0b*daSxayT2j^h7-4YUJ-VvhfekCsPkc5(8= zKbQ*dWqDoR;W=OZCgPYbC&zeSWZ@-)#x9=jgXm^tt(Vu}-zR_HLgKHnJo80K8#fh?W}c#S5zc1|36bi{_WN(OwzzjRZ>`6}19{ zZkJ_|sc6$+k&K{?))e$Ir#T7j;}`q2eZ^Ol0^S{z*(Fgy!dqB$ZQY=1r=Y5bN?7dW zw)G2EjUJ;OrsLb46SQ!;0sJq88?EIGa`%Qe;$J?Ubp)Whu zcC0|{qMrM*u}Qg^WC5#p(|i)K3cOpH9M@XBpRr!^h4h^grcakr;-An4OaU*^#6hmy z+cyXK9C;R7=a&uM%@C8@9Z~0~=SxZGqP?bUksmBF4^T0k1#gL7>BnpSy1pVj?i2lE z+-eyjE=|3U)J@x0O%sLlS>pGXSL6hW7Rz~N_n zEth}$vjX~bxO-ZMB*J?*>EWf~c>l@|RoZ}W_Lu+cbyRnLeRK0Ym9X=e;e1udA^74t z^lH+JnJeZ^_g`-a1hS|Yc5y8F$lUfce5|89;>zuEO-D81Lgs1ozBCZk@bWEr{B3m- zOC^J;nA`7YGAl^Ac=;q8Xw`Ke=z=>Y?*63PVETB))Wz8RPVMstWEe{fFVXXkmewh2 zIHQM&4p*vL&+*+~7`^!Kym*0^xLzdDAzW8_`sJVvz5C)W0!ca4;F8F$1CP!?U^RZ%W{#3fmrj$%Z zzf6F}av*a9ekR_LzN}k=#4K1-Me!ze&g&V|IhiFE?+}&yNSq=)v8y&HZ3z$ zobGtChC3-*pLMGpLZ+hKYy#-nwr=g@c87ggTkHg3#a!#D+? z=Q=gg)MaMy+8rmllfn=2cTp5Gm16#ne2?Ay533kH+FnS9o{6ULHA826Aj3?Jb(_Z6 zk2M~8{@%&`WeFG`Tzb?qG?s9=09N@KZ@Zh9)wvjHV#^o>$@c`7O#Dg_`spqx6uzSM zBCcg}BV3Y7rNHIx?iR+Q;H3S5t8>YAteZ8`aLnAUjLgkDEWRv+jhi`}qNOyzw7)*I zh3hHRqe%|ZJ4WY$YY)&7CYSwv^NHd+#i=3rXKxNBu9QeN9=58}mbq1%Y026*9zzzF z8FBR=O#OICd!m9vpc{ZA@qnNROj>x3jDk^%!jP>t9xa)bDc?QrdR=`Zbyt-YhdPwV zy9*8Fd`{)Idv+_^Vx{Qd$cgdW3Ff6hch8qqd>t=Eo2?&p#cNM69X_fx3O_y6NV7mq zBnw6>PLlqdES9#y)|n3&rK>lgG+`Y>Dm}7Fw~SiV%_c5@Z|*Bcx`slt7kxk@k}LO* z*NAaK2<0y@U~rE3N;~nPdwl7ysw1VC@5erq?`LHkj#jcQMoRMrlqTJ4&RJ&G)Nipj z8ruRX@+74XU2P-PqW!k&y8Vc+p$``?Sz_Rq(TdAk|J}9?(a@dYVlgdad+C}@nIAD6 zHU1f5^*s`$<-~N`uTH$RjwNeQUDF>GW7T^nB8GOB?td4}Cv1fbB!jSO&3Cp4H&$Qf zrCy;1#8 zLk@1t(;~Myw!!6hEH>4ZIVk)b_k&m;doi?Zn^--zBM9yaESJ`q3#Iup!wD(YFFufd zj;|p6N`a_lTft^J^F%o4xPfqwqd9}$tP-I@8JwBZ=RWVP`9Wg%Yd zOn}GaB)L;lvTM~vcA;RlWPkUCd$EN5wf+Jmrf720@X8i!rZj|7;N0A$ zH9O;6-;oUHi}z}rYkXU+HO>&5yhp}(yEcH@xN;|!SFcnhax z%S1kDHp*neWvnFJ?q16}AMp{MZwB!i+RkMCJ^4`0`9bp>P{Pw9YxeY6 z1>knlnwKGj%$tfwJv6a#F5H@P_$3iWK<_c7V?v@Wyn}qAGmZOnQ3)KE{^A>>XUaaeqaJf;^%5uegB;a>f zC($GQul*;8f9vhA&!J+2<;ruueAJ_iD8xP-wO(iNGU)oLj^h~hl*?hliA?biC&&u} zP~m2TImr|3SDr6tf-9%pq!(Dc@!H`LW=csmO4LpJSHbg>wRf$O0(D7N6-ak{np)2U zP39dL*KfDh+*(!5owzG_^ytfn^S7coC4Xdcs?5>uq0+yug{ePYn#Gm0*mkkCf*ib5 zkU4V0l2Qtu0JKq>$6)aOtgj<4Gr+m7Bk=+FAa)mDdP);7pRWd4&kW+egk0iTkKNTzpZ3l%Oc3Yy3yLedrq{8@d%!+=e(cb@Pt4lc zvWsCb-g`!EH1FRzxxR)eN^Q8+_+`1Q!V9SJDl(tqAM(dFLUQJoy`|ub+nVGXr3c;{ z^+P^cYpeI-YFtfJH9Z19mLj(e5yun8WbvdY9h(WP0`xVYBC zH8e5b|3XrrO~BJ;xmAjwbaxrKt9UjxXo@QU(pr^ooP7Ixwdn3+)H?nv8zSZb#e=-B zl*RH`qbLSvMs9@NL@=y*9&g2uBJw#sYD65b4djbTL?J{CdxIya=u&xTTAh&`cHWvAhO zr3?#rxNw57p_)zVm4;1-SPmAiXW#KDBsBc!?AD^#^`Vq?7?QSCr=tbg&5?Tabk9d2 z_OHm$qA>Y}W?Jwj@TfpMqUiH1{Uz5Ha`^1)^AWm(_^vf*NlyGTOZsV4|CA|vo!5_Z zdDld`kusdI<@~1~kG5S|8GO3MjizppDB1600z!1{6ze4uYte86TeD35u21DS>S4XIule;>Q&`sx0rHaElP4VJ`V4JH`|F4ml`ZT zpb1@vwvthnd?-x10o80e+I?H$wb!=-b$@Ry=(i-0s>U7%RH&3v(OcPk`47hK{`@m= zmMI|JQ;plY{ThdTwdSu^@lY1!pgF<3cJoui4aob5P}XX=#aVw-GAzE>PHG4@RMo&PlG!g_kE@uW|QEsShw_MZkE_EqB^{d zqlC>e(Lm*plUt5xL(bx*V_7S-fFF@U<1*1t51}$4hwgc8Gkm9l{k zhn&%K`N<`uj89oat&H=2r7H88HusiL<_hen_*}0v#SXr2H?O_VdxWc1%mr(GM>2D& zNwlb1l?HVVR1j;$Hq#ytzP%T2t6eaj?|a)5;&NecH&;e3^hdmkfi{ z^LumJfcdRU6gU#a3cuC}^vPt^exH)y1S6dyV&_YwNXjwgygRaadl(UM-x)U zBzw+JjHVRDC98TW6y=k}IS6lX;)n>fn#7Osp&+&fF zL+>f=BRBg!e{_HA?%{QC&$X0md0UGLT{?T(iKSd*LO)dWox+s!hkML!X?Ahh!)W@~ z*R+z3IM*s$1`)$=kfAUB+&N|fSj1O^;edo4kjTv>OCg7U?+*R;8~|49xt&^V$g$qg zWB@;=SPFrus+Bx7F(1JU*XHxmd`Si%9Ib6 zT1QJFgo{zo5DBjf%UaAfdj3* zKa$|BZL+}2?wAa6VB6aHz$`ac??GQ-QFPQj>r8=HRB;-R^GQjg1BpnKxEDM?b2I)1 zC_J&8`BrM5>^d|l@|ThLSBp17xE>n(ca8+A_r*zWG?0XA2i{P=ubQo{c&>`| zom?>`@&;2~>Ty}+S!JYp!oYFIi|0BddSXxo8i3Umj7j31j=uVb{Sm^c{;3H6sSn5B z4twBwpCq1jAtubvF@*g@3}n9W+A`OZXZX&+Z>68PFX#Pf=e5?Bp@-HrG@#22DY=z| zwDtibqe-S%NWj+=^6OH>ACs8Cm`l{06?IY1&A6|s280ic<-R<~|A95_D0RV4yM@uVG z3^Zvva6PMHSNt0&c(kKGcNwm$K)M4RE6-jD$vZF)H0{rIDBk^K_fB-uRGz>Ny?gF5 zPl@Dy8N}(4^vfF8iKM@6K}fJH$K01%Te~I!QvLi)gZK;MgSF@7g9;g<`a+e8?2Efl zTZufp=#5_5s?5^v82<*#JS{WVobH{dmpjWxk9;4YQ#IH2aZ+9`%Oe1wpSTqoURxv;(ITO$~OevHji|t&uxjd6ABj3`V4=GyXkz-HYTxy zEu?X#wr~G8P5nM?y!-UG-xz3BX7{>+ct^}!E1}ggMSr$kTQ4BRJZ$TkCp;~EO?xdV zV&M;k10 z866&F3M)_)5m&e$-IM8dFaP26+=&4Ju}5saq~_gXZ>n-%Un!3sQ+lJiZGXBVKVi4Y zG_n3Uzi7go-)r0hGcY$(Uv%OUA-%mPM`WWS|IwH#^zkka&e*IR&2C@A!xKl%_3%M z8VSrHKi)6+Zh{~u1|D>LO4{NwjwHqcQ0Ld*e4#qD2W z%E)>q$$(dk3)qOnl6Vcu3pCgJ2nfO6C$bv>RP`1p_P_Mzf6qiojX-WLUO_-7;b06c znm#XCKn?m1ix4KUCI4O5CKPKY`7Fr(i%ehdGK4QWDPzrED8@%2AuP0g!|>^}4~W9T z!xcrEw;#91`8oEDWcTu6+Hpm{D7qvpjTwac2lV2)l=;;WP;`Pr-k2m%;A^v0rq$nW zV2(aL#+yJF*xethDc}E936O@yv5MyAciaTSr=6!%W*V89Oa39gx{mw?V=*^~)^y8y z#R|Sbnz^~^YFl9WWA4bsM?Sk>xS>|j*Of#-uUQnlU^fyn=3|FnH9027ZzkZBGf`8g z>O}NFb$&nYFX!i1CX(HohiUv<@m=;*j53T#%)h8i(VjX|etEOiYa66Y9>2F(8rdu5 zNUOIunj39lDFG@()h(h=_8&wGUg+lel(h(DgKE z@2S{TT~hx0v$UDBB&D&exfZTbN(ObSCk&Tg#8}bQt>UGkY3evG>NbZKW#OwY7^2z+ zLEC6DORsuSPGbbcrVvDx@M(M-@J_lTGNHgbk#JaGlSh_#+2#J0y(TxFRB^}=XXB5r zqB6v#D{ajb7r3-ZOb_+^VWZQX=iL-5W^*AfuM&L_pmDzBqhd_PxJv;4ctaF`XNkw%zvdZK9JhMTp`rxiz=g?)1aQsvV88Dp8|w_RT2!Ct@e zZgBISMocfafkBb@7kA_5`j;Fz{|1`_|A!h{F!uIe;F-EDL+pQp>o+9-nZHUnAjtug z{iZ;d_V}thZ*WsLJ}Q1zi0N6F0y~e+9}lR)EyTEkgHp1O{8f5##0}@i?6L zko~rtW1(D!b1w)-%d?W~&_UG^7@EBUSs3!G{qik;!Yp;Pq32 z6m1OGjVVFZbp5jy=Gg>)=?QR;Y@GR?rx4$wIR(F2&}8QrQ_OVpr_Em9tCXdf<}3}4 z-S$g1oG3GIl{F|l*?YccYbUC<)`wm>Im$A&R;IaYJK|7x3Wyq!Si4}we6d1rhz!Sn5vJ?s3jclS z|5It_RsX-V>)%VeCW&oo3@;V167oOl*|uAGydSvJA~+>7yX^lUAsk7!A{Lx~hxmaw zy8WDj&M3!>CA`)jbaVE==?XkFUx6HUo2ryxso-Mrf=l{<^Z?ghClm3^RQ~wSsz;hg zbF-*#!q3hP^9)xy`fHh+=An3&X}gFE_9i*a;RQnmLe7Vl5itUhChwIs3-e#$-S6-|uK?Z)7mRCN#U@ zKn5q;H+y;Bj*9dmn~3}`i$A|C*H76yJK!uj9pl6-Ue9%dYtg5j<>9YXFTcUSmpeoo z`Pa9uch6b!q3jWt!`FOyn25#b_XW5JH`Mx5XaoCT{rB9*o}6MYcK5GN^7ndil8k}R^DwM?TN`-ENa0W-*xirZ z@{cQCAm*^gG= zHZGg)=d1#FGv!8}re(^+IvOIr*7IWbx$teSe~>{VVg;x;mxxtQaj`uUt!?1N@;&fT zJ4lU{$o>V^k#!PF{u_CUPH_w;?eG3#@urf>^6*|%BPuyXan!IT0p`#qF*8-RJi7lW zajus6!@Pk5Xpr@`u=HxBYr5(UX ze0*zk*mP4EwD*pCWA)V1qFr3&MbF7XM9RW7_T+SKH$3k8%nQqbMGoJ)tR2qZUmtUM zL9_>M!O~tLu>wr7QSA|@lc&R~SfK|sb2AGz{WeMG^~O}_VRj+DxYC$#<~v6o4>kwa zJ>U(I#FKSfc<7X3w?)N6F(mzw@&n~$HFS^fhlsW2pIf%8#+#RE!)grUlPqF>@{X=6 z3tv1sD_y>U@8KS?jEn4@N%v^nPQgwO@25mysR|dKou(qF-r(+~grDJYVs{og76@=I zX`9YE^X0|xs>6~R0m1CR_!;Yj)If%Cs2Ab3s6e|bfGro=B2eyg$_(+e(^aPoY$<^>jDwP5n+cBd%M?%xExABk>V|< zcvKvj*ZI9Kx>_%YQ+xv5KXO0!4l%r8o$=t&PX0vh)ZV1j0RGhWXyO&!U(v)=B{5fo zEkALx#5tA{#ieRAbL00*NV)W)Nkik4Vl~J+nXV@d=Bf7Y;47Uj5eJ>#t`V1$!fXR= zlr&T?>D`W?CHk5&C}}3*n%8FGvi!_egv+tHa7@x!TZ0cLbTsC+{7n@GHvonxa1W6O z|M-;uQ?SCL4Hy{7)g>WK2Z%u z;m52l^@_S(%z?U<#XRNOE(TL;x-5G$Cn~SPWk_pOF}+drN)QwD-#L zi}RgadSu*YqiV56m{3v#Njfw};x(J0-DM zYCeBr9ZFY_KRIHa!Z^|Su93l38MlZ6ZVRb}9P<~}*fs~&_WMMJs8vKv8Wvh+*YTiT z8LRzc)sWSS>BjnzTd#B-_=w&L!HfF- zE;*I0=A{ZYK6CYjbGIyPYC(Z^9_J`Q_YF%=w~)0Qd`vo-j`jFBB*`PHL(l+-E`=!a zC}mn=v_S1SiSJtKV}H} z`?`~xhv-OJjVF&*b@IbGz1IfPA$$6VZEoDdzVNDt{~WrO00Odb7V5RDCoG z6}H4Lgu_PtI~A18Qf`2Gl_Ry@MM@$dx=?@bR%N54K$V-v;u?gXjlsN?QRS#-OvQ$1 z6I>0{dB>+_yWwL*OQF!vj~EYh%`JRa>z0-e%ov`ddm7B*W=Z=(Q`q_0+F%&W7CmHJ z=e0Qn^O*St$^Cjj4^NTCYGK4Ut(mLFzxoonuWo`YLg5oC${64G@$OmF{+Ie~^b1f$ zsxhqD%SnGeS60a$V}K)jhv)%$&KyCvm;d=@BH`aM-AL!gHu|@Epuzp$XBhtL8C(E_ zH!D`~4xYn1W43ipuWNqIt!ej@7sS>n^;eVu{ta#-rs5^{u? zlt*=e3B3dGE}hD+J1<^I&0}~%r_;InRHCjRKbPrN4$}e>$#5Kt*>i-nc6{g-1_9;a z))%TRZ1*iFvSl`TXcJ^-_wzTU&V_uB4mCyReFTfWuUA&0@kXqT#^=7is6WK%V*Fo^ z;FM0EMX_SFtJ~GvvX7VBxzm7Jjz9$II<9_N_G3$Sa0|)@&&c!TJ?*T32Xa%qCo4?v z*S<6S!Nb>|k=6ym&`9ju!M@$+FuHf3MWnWocBq2Z@TTSKDhy^<`O!E%$Cz zaf!Cvs(J5(I8>~Ee0=XufV@E3ivh0J#aF#gpq_bl>G>{_)>?@2LJO-d zG7e6#<84h!ok@BATwr~^v--Xa_A?wC6lNRx!2--tbOua0%iv?_eN@CsrX-A)15lBc$MP>YdT8#D2{BZmgH??I-z%O`D zs+bs5C}if9OMLWl+M06Na=^iDqV{ii%TH=4@sIgtqY6k~o`C)O=CFBB-R7kdovWtU zof4yg7-`$bEBbT2gDw9s_xumy@dSV{)U$m^7s9NF&<@wm$0&f<(ch+qLF#{?n{ElU z2-6iyXy`4ZXZ`c*r(iSqPJN9l&Ns=koZl_F#;YHHhOH_fPvPNZzVL6H;*9zIfNP@B zkRiW;;(c$_DfDMvowjoJWz}^TEufnhjivq@m;V1@L3KR3nK|n0=^;9vr9obhZ6&WF z=i5*U7aeRvjge->4Y@GfCZ8_W!dmJ#lZKfg2bOYTh=m{CJ*(Nfq3Or@P;~|Ns33TH zO-xvHQ8L9N)6Vs@lHWu+uV{Y*O`W6v+55>y1H~3^zALh$(OBB4OZQ z+-We*mQ@seMua#!dK8i0eMnT;D+Tdok1z<}r-BZO0dq`O&PPPF3tR84JmV8U|yzOJGskPB_L_- z2z+jAI2Ug@XJ8OXro6yf`66w_O#paorANzFa?S`a8!)2O1fev8k@D4zNroewDmVaT zO0eivV3F~er`_V8^oR2(GA*r8u6hg%4&zeA9Q8&5j?KpWN ziX7+aa>M)W0h?)lr%W7Gt!kb`I*K*BZ;ycB!P99OA^n16N&%4kqRxX%IU_~44Jh<% zR&z+PaBQ%eouEvumept@1U`dk(-4@Q*nC2}`|+72(+B@^y{6rA*`bL}3M-!a3R>3IQxeoc;0yO|m^zog=szN^Ov z%ygKb*Tb9m9A7zf@G~e3ycmQU>OQfz0IMQkF>9D%;H|fdk*6iDhNQJU{mC5t;F9QTM8dlalAh7?yXI zm>aKG-+Zp}ZM+K?S>Hn!w@tU$rA*tw7Tv78Mep<}UgT|2{bhH5sV&J^&ugJO_YLe` z&pb)n_aj&2b-3~ZAVy-i-N8tfylo7MO{2x#X>B2SwUZK{2W?xDqGid1uSi2Zd9iZ1 zPz5m>w+`WpxsiUYx}OjNs~X|VSZ^;qwYuYc$`?_BYX^&@v&K9~x*6Tn9_$jfB z$7b*ANEic>aQYt;Hov>k1VZ^gd2g$-pLSLKmSrH~-+DuE(rP)f&P2U}`4X~K>in*O zWK|{hdVdUd102UjYS+uvYp>}fj13NIzk5qK#A$6r(0bl@4CEUwW4lCnjU0_)X1FE(2y2$C1auK|{IYF*F`0)+mY1bCBr2#h)~mYQ#*Lj%w>ns@G* z74d|C49d&S@BUN`!Na8&_a89Z!vBNAbzBqkL}+u<*DfakbL}{KT1J{>>h>@H7ji4& Az5oCK From 02cf6bb3f33ee634c35cf922b217dc5c4b39ce16 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 09:03:53 -0500 Subject: [PATCH 037/140] test ace --- azure-pipelines.yml | 125 +++++++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 283d8b3..5dcfd97 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,6 +20,23 @@ jobs: vmImage: 'windows-latest' steps: + + - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME + displayName: 'Show data sources before ACE' + + - powershell: | + $ProgressPreference = 'SilentlyContinue' + $uri = 'https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe' + irm $uri -outfile ace.exe + $ProgressPreference = 'Continue' + displayName: 'Download ACE' + + - powershell: Start-Process .\ace.exe -Wait -ArgumentList "/quiet /passive /norestart" + displayName: 'Install ACE' + + - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME + displayName: 'Show data sources after ACE' + - powershell: 'Install-Module -Name Pester -Force -SkipPublisherCheck' displayName: 'Update Pester' - powershell: './CI/CI.ps1 -Test' @@ -44,68 +61,68 @@ jobs: targetPath: '$(Build.SourcesDirectory)' artifact: 'Source' - - job: WindowsPSCore - pool: - vmImage: 'windows-latest' + # - job: WindowsPSCore + # pool: + # vmImage: 'windows-latest' - steps: - - pwsh: 'Install-Module -Name Pester -Force' - displayName: 'Update Pester' - - pwsh: './CI/CI.ps1 -Test' - displayName: 'Install and Test' + # steps: + # - pwsh: 'Install-Module -Name Pester -Force' + # displayName: 'Update Pester' + # - pwsh: './CI/CI.ps1 -Test' + # displayName: 'Install and Test' - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'NUnit' - testResultsFiles: '**/TestResults*.xml' - failTaskOnFailedTests: true + # - task: PublishTestResults@2 + # inputs: + # testResultsFormat: 'NUnit' + # testResultsFiles: '**/TestResults*.xml' + # failTaskOnFailedTests: true - - job: Ubuntu - pool: - vmImage: 'ubuntu-latest' + # - job: Ubuntu + # pool: + # vmImage: 'ubuntu-latest' - steps: - - powershell: 'Install-Module -Name Pester -Force' - displayName: 'Update Pester' - - powershell: './CI/CI.ps1 -Test' - displayName: 'Install and Test' + # steps: + # - powershell: 'Install-Module -Name Pester -Force' + # displayName: 'Update Pester' + # - powershell: './CI/CI.ps1 -Test' + # displayName: 'Install and Test' - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'NUnit' - testResultsFiles: '**/TestResults*.xml' - failTaskOnFailedTests: true + # - task: PublishTestResults@2 + # inputs: + # testResultsFormat: 'NUnit' + # testResultsFiles: '**/TestResults*.xml' + # failTaskOnFailedTests: true - - job: macOS - pool: - vmImage: 'macOS-latest' + # - job: macOS + # pool: + # vmImage: 'macOS-latest' - steps: - - script: brew install mono-libgdiplus - displayName: 'Install mono-libgdiplus' - - powershell: 'Install-Module -Name Pester -Force' - displayName: 'Update Pester' - - powershell: './CI/CI.ps1 -Test' - displayName: 'Install and Test' + # steps: + # - script: brew install mono-libgdiplus + # displayName: 'Install mono-libgdiplus' + # - powershell: 'Install-Module -Name Pester -Force' + # displayName: 'Update Pester' + # - powershell: './CI/CI.ps1 -Test' + # displayName: 'Install and Test' - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'NUnit' - testResultsFiles: '**/TestResults*.xml' - failTaskOnFailedTests: true + # - task: PublishTestResults@2 + # inputs: + # testResultsFormat: 'NUnit' + # testResultsFiles: '**/TestResults*.xml' + # failTaskOnFailedTests: true - - job: macOSNoDeps - pool: - vmImage: 'macOS-latest' + # - job: macOSNoDeps + # pool: + # vmImage: 'macOS-latest' - steps: - - powershell: 'Install-Module -Name Pester -Force' - displayName: 'Update Pester' - - powershell: './CI/CI.ps1 -TestImportOnly' - displayName: 'Install and Test Import Only' + # steps: + # - powershell: 'Install-Module -Name Pester -Force' + # displayName: 'Update Pester' + # - powershell: './CI/CI.ps1 -TestImportOnly' + # displayName: 'Install and Test Import Only' - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'NUnit' - testResultsFiles: '**/TestResults*.xml' - failTaskOnFailedTests: true + # - task: PublishTestResults@2 + # inputs: + # testResultsFormat: 'NUnit' + # testResultsFiles: '**/TestResults*.xml' + # failTaskOnFailedTests: true From f1d20ed1638d975282e146dbb0b2ee3c7a73bf28 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 15:13:52 -0500 Subject: [PATCH 038/140] test pipeline cache --- azure-pipelines.yml | 51 ++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5dcfd97..d6348f5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,6 +21,14 @@ jobs: steps: + - task: Cache@2 + inputs: + key: ace + restoreKeys: ace + path: ace.exe + cacheHitVar: CACHE_RESTORED + displayName: Cache ACE + - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME displayName: 'Show data sources before ACE' @@ -30,6 +38,7 @@ jobs: irm $uri -outfile ace.exe $ProgressPreference = 'Continue' displayName: 'Download ACE' + condition: ne(variables.CACHE_RESTORED, 'true') - powershell: Start-Process .\ace.exe -Wait -ArgumentList "/quiet /passive /norestart" displayName: 'Install ACE' @@ -37,29 +46,29 @@ jobs: - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME displayName: 'Show data sources after ACE' - - powershell: 'Install-Module -Name Pester -Force -SkipPublisherCheck' - displayName: 'Update Pester' - - powershell: './CI/CI.ps1 -Test' - displayName: 'Install and Test' + # - powershell: 'Install-Module -Name Pester -Force -SkipPublisherCheck' + # displayName: 'Update Pester' + # - powershell: './CI/CI.ps1 -Test' + # displayName: 'Install and Test' - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'NUnit' - testResultsFiles: '**/TestResults*.xml' - failTaskOnFailedTests: true + # - task: PublishTestResults@2 + # inputs: + # testResultsFormat: 'NUnit' + # testResultsFiles: '**/TestResults*.xml' + # failTaskOnFailedTests: true - - powershell: './CI/CI.ps1 -Artifact' - displayName: 'Prepare Artifact' - - task: PublishPipelineArtifact@1 - inputs: - targetPath: '$(Build.ArtifactStagingDirectory)' - artifact: 'Modules' - - powershell: './CI/CI.ps1 -Analyzer' - displayName: 'Invoke ScriptAnalyzer' - - task: PublishPipelineArtifact@1 - inputs: - targetPath: '$(Build.SourcesDirectory)' - artifact: 'Source' + # - powershell: './CI/CI.ps1 -Artifact' + # displayName: 'Prepare Artifact' + # - task: PublishPipelineArtifact@1 + # inputs: + # targetPath: '$(Build.ArtifactStagingDirectory)' + # artifact: 'Modules' + # - powershell: './CI/CI.ps1 -Analyzer' + # displayName: 'Invoke ScriptAnalyzer' + # - task: PublishPipelineArtifact@1 + # inputs: + # targetPath: '$(Build.SourcesDirectory)' + # artifact: 'Source' # - job: WindowsPSCore # pool: From 72f44ebcb90a32e116a85d2900cdadce5a224c24 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 15:18:37 -0500 Subject: [PATCH 039/140] trying a folder --- azure-pipelines.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d6348f5..ad4a3a5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -25,7 +25,7 @@ jobs: inputs: key: ace restoreKeys: ace - path: ace.exe + path: .\ace cacheHitVar: CACHE_RESTORED displayName: Cache ACE @@ -35,12 +35,13 @@ jobs: - powershell: | $ProgressPreference = 'SilentlyContinue' $uri = 'https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe' - irm $uri -outfile ace.exe + md .\cache + irm $uri -outfile .\ace\ace.exe $ProgressPreference = 'Continue' displayName: 'Download ACE' condition: ne(variables.CACHE_RESTORED, 'true') - - powershell: Start-Process .\ace.exe -Wait -ArgumentList "/quiet /passive /norestart" + - powershell: Start-Process .\ace\ace.exe -Wait -ArgumentList "/quiet /passive /norestart" displayName: 'Install ACE' - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME From ed210cc7302aa5618c0a28b1bff163a016437600 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 15:29:32 -0500 Subject: [PATCH 040/140] testing --- azure-pipelines.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ad4a3a5..2435e5e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -19,13 +19,17 @@ jobs: pool: vmImage: 'windows-latest' + variables: + ACE_FOLDER: $(Pipeline.Workspace)/ACE + steps: - task: Cache@2 inputs: - key: ace - restoreKeys: ace - path: .\ace + key: 'ace | "$(Agent.OS)" | ace.exe' + restoreKeys: | + ace | "$(Agent.OS)" + path: $(ACE_FOLDER) cacheHitVar: CACHE_RESTORED displayName: Cache ACE @@ -35,8 +39,8 @@ jobs: - powershell: | $ProgressPreference = 'SilentlyContinue' $uri = 'https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe' - md .\cache - irm $uri -outfile .\ace\ace.exe + md $(ACE_FOLDER) + irm $uri -outfile (join-path $(ACE_FOLDER) ace.exe) $ProgressPreference = 'Continue' displayName: 'Download ACE' condition: ne(variables.CACHE_RESTORED, 'true') From c567526eac05aa0fb5e6af22f73d037656cae803 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 15:34:36 -0500 Subject: [PATCH 041/140] testing caching --- azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2435e5e..4002560 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -39,13 +39,13 @@ jobs: - powershell: | $ProgressPreference = 'SilentlyContinue' $uri = 'https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe' - md $(ACE_FOLDER) - irm $uri -outfile (join-path $(ACE_FOLDER) ace.exe) + md $env:ACE_FOLDER + irm $uri -outfile (join-path $env:ACE_FOLDER ace.exe) $ProgressPreference = 'Continue' displayName: 'Download ACE' condition: ne(variables.CACHE_RESTORED, 'true') - - powershell: Start-Process .\ace\ace.exe -Wait -ArgumentList "/quiet /passive /norestart" + - powershell: Start-Process (join-path $env:ACE_FOLDER ace.exe) -Wait -ArgumentList "/quiet /passive /norestart" displayName: 'Install ACE' - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME From 6d97efc5c2db8181689b453f41eccc4796f6f6a6 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 15:43:57 -0500 Subject: [PATCH 042/140] fun with curl... maybe --- azure-pipelines.yml | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4002560..67c5b0d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -19,29 +19,19 @@ jobs: pool: vmImage: 'windows-latest' - variables: - ACE_FOLDER: $(Pipeline.Workspace)/ACE - steps: - task: Cache@2 inputs: - key: 'ace | "$(Agent.OS)" | ace.exe' - restoreKeys: | - ace | "$(Agent.OS)" - path: $(ACE_FOLDER) + key: 'v2 | ace | "$(Agent.OS)" | ace.exe' + path: $(Pipeline.Workspace) cacheHitVar: CACHE_RESTORED displayName: Cache ACE - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME displayName: 'Show data sources before ACE' - - powershell: | - $ProgressPreference = 'SilentlyContinue' - $uri = 'https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe' - md $env:ACE_FOLDER - irm $uri -outfile (join-path $env:ACE_FOLDER ace.exe) - $ProgressPreference = 'Continue' + - bash: curl -o ace.exe https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe displayName: 'Download ACE' condition: ne(variables.CACHE_RESTORED, 'true') From eb63fe259a9cc8ebd7bddf71dc55ad36a6e4a35c Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 16:02:19 -0500 Subject: [PATCH 043/140] testing caching --- azure-pipelines.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 67c5b0d..bea1488 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -23,19 +23,21 @@ jobs: - task: Cache@2 inputs: - key: 'v2 | ace | "$(Agent.OS)" | ace.exe' - path: $(Pipeline.Workspace) + key: v2 | ace + path: /ace cacheHitVar: CACHE_RESTORED displayName: Cache ACE + - bash: | + mkdir ./ace + curl -o ./ace/ace.exe https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe + displayName: 'Download ACE' + condition: ne(variables.CACHE_RESTORED, 'true') + - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME displayName: 'Show data sources before ACE' - - bash: curl -o ace.exe https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe - displayName: 'Download ACE' - condition: ne(variables.CACHE_RESTORED, 'true') - - - powershell: Start-Process (join-path $env:ACE_FOLDER ace.exe) -Wait -ArgumentList "/quiet /passive /norestart" + - powershell: Start-Process ./ace/ace.exe -Wait -ArgumentList "/quiet /passive /norestart" displayName: 'Install ACE' - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME From 88e28a1d6c21d0b35aff40ab005f8f1959ba4163 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 16:05:33 -0500 Subject: [PATCH 044/140] change path --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bea1488..b6e298d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -24,7 +24,7 @@ jobs: - task: Cache@2 inputs: key: v2 | ace - path: /ace + path: ace cacheHitVar: CACHE_RESTORED displayName: Cache ACE From 08bf87753521d6c194ed7f0c548310aeb3c03c6e Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 16:11:32 -0500 Subject: [PATCH 045/140] add back in normal win testing --- azure-pipelines.yml | 50 ++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b6e298d..66ac8bf 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -34,38 +34,32 @@ jobs: displayName: 'Download ACE' condition: ne(variables.CACHE_RESTORED, 'true') - - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME - displayName: 'Show data sources before ACE' - - powershell: Start-Process ./ace/ace.exe -Wait -ArgumentList "/quiet /passive /norestart" - displayName: 'Install ACE' + displayName: 'Install ACE for Invoke-ExcelQuery testing' - - powershell: (New-Object system.data.oledb.oledbenumerator).GetElements().SOURCES_NAME - displayName: 'Show data sources after ACE' + - powershell: 'Install-Module -Name Pester -Force -SkipPublisherCheck' + displayName: 'Update Pester' + - powershell: './CI/CI.ps1 -Test' + displayName: 'Install and Test' - # - powershell: 'Install-Module -Name Pester -Force -SkipPublisherCheck' - # displayName: 'Update Pester' - # - powershell: './CI/CI.ps1 -Test' - # displayName: 'Install and Test' + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '**/TestResults*.xml' + failTaskOnFailedTests: true - # - task: PublishTestResults@2 - # inputs: - # testResultsFormat: 'NUnit' - # testResultsFiles: '**/TestResults*.xml' - # failTaskOnFailedTests: true - - # - powershell: './CI/CI.ps1 -Artifact' - # displayName: 'Prepare Artifact' - # - task: PublishPipelineArtifact@1 - # inputs: - # targetPath: '$(Build.ArtifactStagingDirectory)' - # artifact: 'Modules' - # - powershell: './CI/CI.ps1 -Analyzer' - # displayName: 'Invoke ScriptAnalyzer' - # - task: PublishPipelineArtifact@1 - # inputs: - # targetPath: '$(Build.SourcesDirectory)' - # artifact: 'Source' + - powershell: './CI/CI.ps1 -Artifact' + displayName: 'Prepare Artifact' + - task: PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)' + artifact: 'Modules' + - powershell: './CI/CI.ps1 -Analyzer' + displayName: 'Invoke ScriptAnalyzer' + - task: PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.SourcesDirectory)' + artifact: 'Source' # - job: WindowsPSCore # pool: From 877310e0157078e85473afd60119b31438c58bf2 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 16:20:59 -0500 Subject: [PATCH 046/140] add back pscore --- azure-pipelines.yml | 48 ++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 66ac8bf..eaecba2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,9 +21,10 @@ jobs: steps: + # BEGIN - ACE support for Invoke-ExcelQuery testing - task: Cache@2 inputs: - key: v2 | ace + key: v2 | "$(Agent.OS)" | ace path: ace cacheHitVar: CACHE_RESTORED displayName: Cache ACE @@ -36,6 +37,7 @@ jobs: - powershell: Start-Process ./ace/ace.exe -Wait -ArgumentList "/quiet /passive /norestart" displayName: 'Install ACE for Invoke-ExcelQuery testing' + # END - ACE support for Invoke-ExcelQuery testing - powershell: 'Install-Module -Name Pester -Force -SkipPublisherCheck' displayName: 'Update Pester' @@ -61,21 +63,39 @@ jobs: targetPath: '$(Build.SourcesDirectory)' artifact: 'Source' - # - job: WindowsPSCore - # pool: - # vmImage: 'windows-latest' + - job: WindowsPSCore + pool: + vmImage: 'windows-latest' - # steps: - # - pwsh: 'Install-Module -Name Pester -Force' - # displayName: 'Update Pester' - # - pwsh: './CI/CI.ps1 -Test' - # displayName: 'Install and Test' + # BEGIN - ACE support for Invoke-ExcelQuery testing + - task: Cache@2 + inputs: + key: v2 | "$(Agent.OS)" | ace + path: ace + cacheHitVar: CACHE_RESTORED + displayName: Cache ACE - # - task: PublishTestResults@2 - # inputs: - # testResultsFormat: 'NUnit' - # testResultsFiles: '**/TestResults*.xml' - # failTaskOnFailedTests: true + - bash: | + mkdir ./ace + curl -o ./ace/ace.exe https://download.microsoft.com/download/3/5/C/35C84C36-661A-44E6-9324-8786B8DBE231/accessdatabaseengine_X64.exe + displayName: 'Download ACE' + condition: ne(variables.CACHE_RESTORED, 'true') + + - powershell: Start-Process ./ace/ace.exe -Wait -ArgumentList "/quiet /passive /norestart" + displayName: 'Install ACE for Invoke-ExcelQuery testing' + # END - ACE support for Invoke-ExcelQuery testing + + steps: + - pwsh: 'Install-Module -Name Pester -Force' + displayName: 'Update Pester' + - pwsh: './CI/CI.ps1 -Test' + displayName: 'Install and Test' + + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '**/TestResults*.xml' + failTaskOnFailedTests: true # - job: Ubuntu # pool: From 956cf5aa49175a294a83309aec76559ab96939b9 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 16:23:54 -0500 Subject: [PATCH 047/140] fix --- azure-pipelines.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index eaecba2..506edde 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -67,6 +67,8 @@ jobs: pool: vmImage: 'windows-latest' + steps: + # BEGIN - ACE support for Invoke-ExcelQuery testing - task: Cache@2 inputs: @@ -85,7 +87,6 @@ jobs: displayName: 'Install ACE for Invoke-ExcelQuery testing' # END - ACE support for Invoke-ExcelQuery testing - steps: - pwsh: 'Install-Module -Name Pester -Force' displayName: 'Update Pester' - pwsh: './CI/CI.ps1 -Test' From 00f72781151073655b6455e1276b088535890a39 Mon Sep 17 00:00:00 2001 From: Roy Ashbrook Date: Tue, 16 Nov 2021 16:28:03 -0500 Subject: [PATCH 048/140] add back *nix tests --- azure-pipelines.yml | 82 ++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 506edde..f64f914 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -98,52 +98,52 @@ jobs: testResultsFiles: '**/TestResults*.xml' failTaskOnFailedTests: true - # - job: Ubuntu - # pool: - # vmImage: 'ubuntu-latest' + - job: Ubuntu + pool: + vmImage: 'ubuntu-latest' - # steps: - # - powershell: 'Install-Module -Name Pester -Force' - # displayName: 'Update Pester' - # - powershell: './CI/CI.ps1 -Test' - # displayName: 'Install and Test' + steps: + - powershell: 'Install-Module -Name Pester -Force' + displayName: 'Update Pester' + - powershell: './CI/CI.ps1 -Test' + displayName: 'Install and Test' - # - task: PublishTestResults@2 - # inputs: - # testResultsFormat: 'NUnit' - # testResultsFiles: '**/TestResults*.xml' - # failTaskOnFailedTests: true + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '**/TestResults*.xml' + failTaskOnFailedTests: true - # - job: macOS - # pool: - # vmImage: 'macOS-latest' + - job: macOS + pool: + vmImage: 'macOS-latest' - # steps: - # - script: brew install mono-libgdiplus - # displayName: 'Install mono-libgdiplus' - # - powershell: 'Install-Module -Name Pester -Force' - # displayName: 'Update Pester' - # - powershell: './CI/CI.ps1 -Test' - # displayName: 'Install and Test' + steps: + - script: brew install mono-libgdiplus + displayName: 'Install mono-libgdiplus' + - powershell: 'Install-Module -Name Pester -Force' + displayName: 'Update Pester' + - powershell: './CI/CI.ps1 -Test' + displayName: 'Install and Test' - # - task: PublishTestResults@2 - # inputs: - # testResultsFormat: 'NUnit' - # testResultsFiles: '**/TestResults*.xml' - # failTaskOnFailedTests: true + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '**/TestResults*.xml' + failTaskOnFailedTests: true - # - job: macOSNoDeps - # pool: - # vmImage: 'macOS-latest' + - job: macOSNoDeps + pool: + vmImage: 'macOS-latest' - # steps: - # - powershell: 'Install-Module -Name Pester -Force' - # displayName: 'Update Pester' - # - powershell: './CI/CI.ps1 -TestImportOnly' - # displayName: 'Install and Test Import Only' + steps: + - powershell: 'Install-Module -Name Pester -Force' + displayName: 'Update Pester' + - powershell: './CI/CI.ps1 -TestImportOnly' + displayName: 'Install and Test Import Only' - # - task: PublishTestResults@2 - # inputs: - # testResultsFormat: 'NUnit' - # testResultsFiles: '**/TestResults*.xml' - # failTaskOnFailedTests: true + - task: PublishTestResults@2 + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '**/TestResults*.xml' + failTaskOnFailedTests: true From 73fc96166c63740863c45bc3d4156c1d6d37bbce Mon Sep 17 00:00:00 2001 From: muschebubusche <65829739+muschebubusche@users.noreply.github.com> Date: Sat, 20 Nov 2021 16:51:40 +0100 Subject: [PATCH 049/140] Refactor selective column import Move code into the function Get-PropertyNames and remove the rest. Now it only replaces $Columns with $ImportColumns after a couple of checks. So the heavy work like arranging and getting the right values is done in the original way of Import-Excel. --- Public/Import-Excel.ps1 | 88 ++++++----------------------------------- 1 file changed, 11 insertions(+), 77 deletions(-) diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index d71792b..67cfc0c 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -63,6 +63,16 @@ ) try { + if ($ImportColumns) { + $end = $Worksheet.Dimension.End.Column + # Check $ImportColumns + if ($ImportColumns[0] -le 0) { throw "The first entry in ImportColumns must be equal or greater 1" ; return } + # Check $StartColumn and $EndColumn + if (($StartColumn -ne 1) -or ($EndColumn -ne $end)) { Write-Warning -Message "If ImportColumns is set than individual StartColumn and EndColumn will be ignored." } + # Replace $Columns with $ImportColumns + $Columns = $ImportColumns + } + if ($HeaderName) { $i = 0 foreach ($H in $HeaderName) { @@ -93,26 +103,6 @@ throw "Failed creating property names: $_" ; return } } - function Clear-ExcelPackage { - <# - .SYNOPSIS - Clear given ExcelPackage from specified columns. - #> - param ( - # Column from where the cleaning will start. - [Parameter(Mandatory)] - [Int] - $Start, - # Count of columns that will be removed. - [Parameter(Mandatory)] - [Int] - $Count - ) - - $Worksheet.DeleteColumn($Start, $Count) - # Return $ExcelPackage to update the variable - return $ExcelPackage - } foreach ($Path in $Paths) { if ($path) { $extension = [System.IO.Path]::GetExtension($Path) @@ -162,63 +152,7 @@ $columns = ($StartColumn..$EndColumn).Where( { $colHash[$_] }) } else { - if ($ImportColumns) { - # Safe the original array because $ImportColumns needs to be sorted for calculation - $tempArray = $ImportColumns - $ImportColumns = $ImportColumns | Sort-Object - # Check order - if (($tempArray[0] -ne $ImportColumns[0]) -or ($tempArray[$tempArray.Count - 1] -ne $ImportColumns[$ImportColumns.Count - 1])) { - $arrange = $true - } else { - for ($i = 0; $i -lt $ImportColumns.Count; $i++) { - if ($ImportColumns[$i] -ne $tempArray[$i]) { $arrange = $true;break } - } - } - $end = $Worksheet.Dimension.End.Column - if (($StartColumn -ne 1) -or ($EndColumn -ne $end)) { Write-Warning -Message "If ImportColumns is set than individual StartColumn and EndColumn will be ignored." } - # Variable to store all removed columns - $removedColumns = 0 - # Preparation run - $start = 1 - $count = $ImportColumns[0] - 1 - $ExcelPackage = Clear-ExcelPackage -Start $start -Count $count - $removedColumns = $removedColumns + $count - for ($i = 0; $i -lt $ImportColumns.Count; $i++) { - # Check if the current iteration is the last one for cleanup meassures - if ($i -eq ($ImportColumns.Count - 1)) { $lastLoop = $true } - if ($lastLoop) { - # Only clean up if the endcolumn does not match the last entry in the $ImportColumns array - if ($ImportColumns[$i] -ne $end) { - $start = $ImportColumns.Count + 1 - $count = $end - ($removedColumns + $ImportColumns.Count) - } else { - # This means that the endcolumn gets imported - continue - } - } else { - # Calculate the StartColumn and ColumnCount for the removal - $start = ($i + 1) + 1 # 1 is from the preparation run - $count = $ImportColumns[$i + 1] - ($removedColumns + $start) - $removedColumns = $removedColumns + $count - } - $ExcelPackage = Clear-ExcelPackage -Start $start -Count $count - } - # Arrange columns accordingly to $ImportColumns - if ($arrange) { - for ($i = 0; $i -lt $ImportColumns.Count; $i++) { - $srcCol = [array]::IndexOf($ImportColumns,$tempArray[$i]) + 1 - $destCol = $ImportColumns.Count + ($i + 1) - $Worksheet.Cells[1,$srcCol,$EndRow,$srcCol].Copy(($Worksheet.Cells[1,$destCol,$EndRow,$destCol])) - } - $ExcelPackage = Clear-ExcelPackage -Start 1 -Count $ImportColumns.Count - Remove-Variable -Name 'tempArray' - } - # Create new array out of the $ImportColumns.Count for the further processing - $columns = 1..$ImportColumns.Count - } - else { - $Columns = $StartColumn .. $EndColumn ; if ($StartColumn -gt $EndColumn) { Write-Warning -Message "Selecting columns $StartColumn to $EndColumn might give odd results." } - } + $Columns = $StartColumn .. $EndColumn ; if ($StartColumn -gt $EndColumn) { Write-Warning -Message "Selecting columns $StartColumn to $EndColumn might give odd results." } if ($NoHeader) { $rows = $StartRow..$EndRow ; if ($StartRow -gt $EndRow) { Write-Warning -Message "Selecting rows $StartRow to $EndRow might give odd results." } } elseif ($HeaderName) { $rows = $StartRow..$EndRow } else { From b33a282740ff8f2acb93cd0dd8155d8f259659bc Mon Sep 17 00:00:00 2001 From: muschebubusche <65829739+muschebubusche@users.noreply.github.com> Date: Sat, 20 Nov 2021 16:51:49 +0100 Subject: [PATCH 050/140] Add new pester test --- __tests__/ImportExcelHeaderName.tests.ps1 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/__tests__/ImportExcelHeaderName.tests.ps1 b/__tests__/ImportExcelHeaderName.tests.ps1 index 9ee4e4b..41944df 100644 --- a/__tests__/ImportExcelHeaderName.tests.ps1 +++ b/__tests__/ImportExcelHeaderName.tests.ps1 @@ -378,4 +378,18 @@ Describe "Import-Excel on a sheet with no headings" { $actual[0].A | Should -Be '1' $actual[0].D | Should -Be '4' } + + It "Should arrange the columns if -ImportColumns is not in order and -NoHeader is used" { + $actual = @(Import-Excel $xlfileImportColumns -ImportColumns @(5,1,4) -NoHeader -StartRow 2) + $actualNames = $actual[0].psobject.properties.Name + + $actualNames.Count | Should -Be 3 + $actualNames[0] | Should -Be 'P1' + $actualNames[1] | Should -Be 'P2' + $actualNames[2] | Should -Be 'P3' + + $actual[0].P1 | Should -Be '5' + $actual[0].P2 | Should -Be '1' + $actual[0].P3 | Should -Be '4' + } } \ No newline at end of file From 536cdaa841855ad648a1809b0e2c95c521d01d9c Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 20 Nov 2021 15:53:23 -0500 Subject: [PATCH 051/140] tweaked spelling --- Public/Import-Excel.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index 67cfc0c..adadc82 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -68,7 +68,7 @@ # Check $ImportColumns if ($ImportColumns[0] -le 0) { throw "The first entry in ImportColumns must be equal or greater 1" ; return } # Check $StartColumn and $EndColumn - if (($StartColumn -ne 1) -or ($EndColumn -ne $end)) { Write-Warning -Message "If ImportColumns is set than individual StartColumn and EndColumn will be ignored." } + if (($StartColumn -ne 1) -or ($EndColumn -ne $end)) { Write-Warning -Message "If ImportColumns is set, then individual StartColumn and EndColumn will be ignored." } # Replace $Columns with $ImportColumns $Columns = $ImportColumns } @@ -95,7 +95,7 @@ foreach ($C in $Columns) { #allow "False" or "0" to be column headings - $Worksheet.Cells[$StartRow, $C] | Where-Object {-not [string]::IsNullOrEmpty($_.Value) } | Select-Object @{N = 'Column'; E = { $C } }, Value + $Worksheet.Cells[$StartRow, $C] | Where-Object { -not [string]::IsNullOrEmpty($_.Value) } | Select-Object @{N = 'Column'; E = { $C } }, Value } } } @@ -196,7 +196,7 @@ } $TextColRegEx = New-Object -TypeName regex -ArgumentList $TextColExpression , 9 } - else {$TextColRegEx = $null} + else { $TextColRegEx = $null } foreach ($R in $rows) { #Disabled write-verbose for speed # Write-Verbose "Import row '$R'" @@ -205,12 +205,12 @@ foreach ($P in $PropertyNames) { $MatchTest = $TextColRegEx.Match($P.value) if ($MatchTest.groups.name -eq "astext") { - $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Text + $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Text } elseif ($MatchTest.groups.name -eq "asdate" -and $Worksheet.Cells[$R, $P.Column].Value -is [System.ValueType]) { - $NewRow[$P.Value] = [datetime]::FromOADate(($Worksheet.Cells[$R, $P.Column].Value)) + $NewRow[$P.Value] = [datetime]::FromOADate(($Worksheet.Cells[$R, $P.Column].Value)) } - else { $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value } + else { $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value } } } else { From 42cb5a316a112156145973f932f21b7ae3ea4233 Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 20 Nov 2021 16:18:05 -0500 Subject: [PATCH 052/140] update changelog --- changelog.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/changelog.md b/changelog.md index 7507581..e504eda 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,12 @@ +# v7.4.0 + +- Thank you to [Max Goczall](https://github.com/muschebubusche) for this contribution! + - `ImportColumns` parameter added to `ImportExcel`. It is used to define which columns of the ExcelPackage should be imported. + +```powershell +Import-Excel -Path $xlFile -ImportColumns @(6,7,12,25,46) +``` + # v7.3.1 - Added query Excel spreadsheets, with SQL queries! From 3a4c2d7bd910a3fe5b9ae21da20cf15c34b81bcb Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 20 Nov 2021 16:18:12 -0500 Subject: [PATCH 053/140] bump version --- ImportExcel.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index b190043..59e1612 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.3.1' + ModuleVersion = '7.4.0' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' From 9eb894cf5963f5c797ce0aae120bf2e0c1595c1c Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Sun, 21 Nov 2021 16:50:34 -0800 Subject: [PATCH 054/140] create directory, add initial md file w/first doc --- FAQ/How to Read an Existing Excel File.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 FAQ/How to Read an Existing Excel File.md diff --git a/FAQ/How to Read an Existing Excel File.md b/FAQ/How to Read an Existing Excel File.md new file mode 100644 index 0000000..93fc469 --- /dev/null +++ b/FAQ/How to Read an Existing Excel File.md @@ -0,0 +1,12 @@ +# How to Read an existing Excel File + +```powershell +Import-Module ImportExcel +#Loads the Excel file into a is a custom PS Object +$ExcelFile = Import-Excel "C:\Test\file.xlsx" -WorksheetName "Sheet1" +``` + +## Visual of Data Structure +The File C:\Test\file.xlsx contains + +After Loading this data into ```$ExcelFile``` the data is stored like: \ No newline at end of file From 1aa5c6da45ba047708c5c9c5f58b11a188404933 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Sun, 21 Nov 2021 16:51:14 -0800 Subject: [PATCH 055/140] add initial 2 images for first md FAQ doc --- images/FAQ_Images/ExcelFileContents.png | Bin 0 -> 4369 bytes images/FAQ_Images/ExcelFileDebugImg.jpg | Bin 0 -> 12092 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/FAQ_Images/ExcelFileContents.png create mode 100644 images/FAQ_Images/ExcelFileDebugImg.jpg diff --git a/images/FAQ_Images/ExcelFileContents.png b/images/FAQ_Images/ExcelFileContents.png new file mode 100644 index 0000000000000000000000000000000000000000..d950cbe3fc6312c6633849e97f00782eee6abd15 GIT binary patch literal 4369 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 literal 0 HcmV?d00001 diff --git a/images/FAQ_Images/ExcelFileDebugImg.jpg b/images/FAQ_Images/ExcelFileDebugImg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..310726349f50f1fe5bc73741537805d3358bda05 GIT binary patch literal 12092 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 Date: Sun, 21 Nov 2021 16:56:52 -0800 Subject: [PATCH 056/140] Add first 2 images Images display debugger and contents of excel file. --- FAQ/How to Read an Existing Excel File.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/FAQ/How to Read an Existing Excel File.md b/FAQ/How to Read an Existing Excel File.md index 93fc469..5e10cf6 100644 --- a/FAQ/How to Read an Existing Excel File.md +++ b/FAQ/How to Read an Existing Excel File.md @@ -7,6 +7,8 @@ $ExcelFile = Import-Excel "C:\Test\file.xlsx" -WorksheetName "Sheet1" ``` ## Visual of Data Structure -The File C:\Test\file.xlsx contains +The File C:\Test\file.xlsx contains +![alt text](https://github.com/DavisHenckel/ImportExcel/blob/FAQ_Docs/images/FAQ_Images/ExcelFileContents.png) -After Loading this data into ```$ExcelFile``` the data is stored like: \ No newline at end of file +After Loading this data into ```$ExcelFile``` the data is stored like: +![alt text](https://github.com/DavisHenckel/ImportExcel/blob/FAQ_Docs/images/FAQ_Images/ExcelFileDebugImg.jpg) From 330e237727df6f0bec6048ba9a12e3f7ee8b132f Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 06:31:53 -0800 Subject: [PATCH 057/140] Update Image Paths so they are Relative --- FAQ/How to Read an Existing Excel File.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FAQ/How to Read an Existing Excel File.md b/FAQ/How to Read an Existing Excel File.md index 5e10cf6..2bf246c 100644 --- a/FAQ/How to Read an Existing Excel File.md +++ b/FAQ/How to Read an Existing Excel File.md @@ -8,7 +8,7 @@ $ExcelFile = Import-Excel "C:\Test\file.xlsx" -WorksheetName "Sheet1" ## Visual of Data Structure The File C:\Test\file.xlsx contains -![alt text](https://github.com/DavisHenckel/ImportExcel/blob/FAQ_Docs/images/FAQ_Images/ExcelFileContents.png) +![ExcelFileContents](/images/FAQ_Images/ExcelFileContents.png) After Loading this data into ```$ExcelFile``` the data is stored like: -![alt text](https://github.com/DavisHenckel/ImportExcel/blob/FAQ_Docs/images/FAQ_Images/ExcelFileDebugImg.jpg) +![ExcelFileDebugImg](/images/FAQ_Images/ExcelFileDebugImg.jpg) From e9b437af4e20b5542911140e629e321967b1b899 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 06:56:08 -0800 Subject: [PATCH 058/140] Complete first version of ExistingExcelFile FAQ Added loading a row/col, then mapping to HashTable --- FAQ/How to Read an Existing Excel File.md | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/FAQ/How to Read an Existing Excel File.md b/FAQ/How to Read an Existing Excel File.md index 2bf246c..7a633e8 100644 --- a/FAQ/How to Read an Existing Excel File.md +++ b/FAQ/How to Read an Existing Excel File.md @@ -12,3 +12,29 @@ The File C:\Test\file.xlsx contains After Loading this data into ```$ExcelFile``` the data is stored like: ![ExcelFileDebugImg](/images/FAQ_Images/ExcelFileDebugImg.jpg) + +## Other Common Operations + +### Load a Column +```powershell +$SpecificColumn = $ExcelFile."anotherHeader" #loads column with the header "another header" store into an array +``` + +### Load a Row +```powershell +$SpecificRow = $ExcelFile[1] #Loads row at index 1. Index 1 is the first row instead of 0. +``` + +### Map Contents to HashTable to interpret data +Sometimes mapping to a HashTable is more convenient to have access to common Hashtable operations. Enumerate a HashTable with the Row data properties by: +```powershell +$HashTable = @{} +$SpecificRow= $ExcelFile[2] +$SpecificRow.psobject.properties | ForEach-Object {$HashTable[$_.Name] = $_.Value} +``` +To then iterate through the enumerated hash... +```powershell +ForEach ($Key in ($HashTable.GetEnumerator()) | Where-Object {$_.Value -eq "x"}){ #Only grabs a key where the value is "x" + #values accessible with $Key.Name or $Key.Value +} +``` From 8905b8d401cff25fce7e12e03f41521b512a3eda Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 08:58:44 -0800 Subject: [PATCH 059/140] Fix small typo Comment in first image should have read "#Loads the Excel file into a PSCustomObject" --- FAQ/How to Read an Existing Excel File.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FAQ/How to Read an Existing Excel File.md b/FAQ/How to Read an Existing Excel File.md index 7a633e8..99a1b92 100644 --- a/FAQ/How to Read an Existing Excel File.md +++ b/FAQ/How to Read an Existing Excel File.md @@ -2,7 +2,7 @@ ```powershell Import-Module ImportExcel -#Loads the Excel file into a is a custom PS Object +#Loads the Excel file into a PSCustomObject $ExcelFile = Import-Excel "C:\Test\file.xlsx" -WorksheetName "Sheet1" ``` @@ -17,7 +17,7 @@ After Loading this data into ```$ExcelFile``` the data is stored like: ### Load a Column ```powershell -$SpecificColumn = $ExcelFile."anotherHeader" #loads column with the header "another header" store into an array +$SpecificColumn = $ExcelFile."anotherHeader" #loads column with the header "anotherHeader" Data stored in an array ``` ### Load a Row From 15211a62972b6b40526d9a4a937169e4ee974fca Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 09:08:31 -0800 Subject: [PATCH 060/140] Update Wording. Punctuation and wording changes. --- FAQ/How to Read an Existing Excel File.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FAQ/How to Read an Existing Excel File.md b/FAQ/How to Read an Existing Excel File.md index 99a1b92..577441c 100644 --- a/FAQ/How to Read an Existing Excel File.md +++ b/FAQ/How to Read an Existing Excel File.md @@ -17,7 +17,7 @@ After Loading this data into ```$ExcelFile``` the data is stored like: ### Load a Column ```powershell -$SpecificColumn = $ExcelFile."anotherHeader" #loads column with the header "anotherHeader" Data stored in an array +$SpecificColumn = $ExcelFile."anotherHeader" #loads column with the header "anotherHeader" -- data stored in an array ``` ### Load a Row @@ -25,8 +25,8 @@ $SpecificColumn = $ExcelFile."anotherHeader" #loads column with the header "anot $SpecificRow = $ExcelFile[1] #Loads row at index 1. Index 1 is the first row instead of 0. ``` -### Map Contents to HashTable to interpret data -Sometimes mapping to a HashTable is more convenient to have access to common Hashtable operations. Enumerate a HashTable with the Row data properties by: +### Map Contents to Hashtable to interpret data +Sometimes mapping to a HashTable is more convenient to have access to common Hashtable operations. Enumerate a Hashtable with the row's data by: ```powershell $HashTable = @{} $SpecificRow= $ExcelFile[2] From 283e50547df49ee80ffb2149dd67d1315ffc1f40 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 09:11:56 -0800 Subject: [PATCH 061/140] Styling Consistency & Punctuation --- FAQ/How to Read an Existing Excel File.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/FAQ/How to Read an Existing Excel File.md b/FAQ/How to Read an Existing Excel File.md index 577441c..30ad946 100644 --- a/FAQ/How to Read an Existing Excel File.md +++ b/FAQ/How to Read an Existing Excel File.md @@ -1,4 +1,4 @@ -# How to Read an existing Excel File +# How to Read an Existing Excel File ```powershell Import-Module ImportExcel @@ -10,7 +10,7 @@ $ExcelFile = Import-Excel "C:\Test\file.xlsx" -WorksheetName "Sheet1" The File C:\Test\file.xlsx contains ![ExcelFileContents](/images/FAQ_Images/ExcelFileContents.png) -After Loading this data into ```$ExcelFile``` the data is stored like: +After loading this data into ```$ExcelFile``` the data is stored like: ![ExcelFileDebugImg](/images/FAQ_Images/ExcelFileDebugImg.jpg) ## Other Common Operations @@ -25,14 +25,14 @@ $SpecificColumn = $ExcelFile."anotherHeader" #loads column with the header "anot $SpecificRow = $ExcelFile[1] #Loads row at index 1. Index 1 is the first row instead of 0. ``` -### Map Contents to Hashtable to interpret data -Sometimes mapping to a HashTable is more convenient to have access to common Hashtable operations. Enumerate a Hashtable with the row's data by: +### Map Contents to Hashtable to Interpret Data +Sometimes mapping to a Hashtable is more convenient to have access to common Hashtable operations. Enumerate a Hashtable with the row's data by: ```powershell $HashTable = @{} $SpecificRow= $ExcelFile[2] $SpecificRow.psobject.properties | ForEach-Object {$HashTable[$_.Name] = $_.Value} ``` -To then iterate through the enumerated hash... +To then iterate through the enumerated Hashtable: ```powershell ForEach ($Key in ($HashTable.GetEnumerator()) | Where-Object {$_.Value -eq "x"}){ #Only grabs a key where the value is "x" #values accessible with $Key.Name or $Key.Value From 1fd2f422cda1756a8a492cc5bc77865e2c227d5a Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 10:15:01 -0800 Subject: [PATCH 062/140] Create 2 more MD files to create --- FAQ/How to Create an Empty Excel File.md | 0 FAQ/How to Write to an Existing Excel File.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 FAQ/How to Create an Empty Excel File.md create mode 100644 FAQ/How to Write to an Existing Excel File.md diff --git a/FAQ/How to Create an Empty Excel File.md b/FAQ/How to Create an Empty Excel File.md new file mode 100644 index 0000000..e69de29 diff --git a/FAQ/How to Write to an Existing Excel File.md b/FAQ/How to Write to an Existing Excel File.md new file mode 100644 index 0000000..e69de29 From d706a1027676decb5c1f59488cbf875fb8715db7 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 10:23:09 -0800 Subject: [PATCH 063/140] Complete Document Demonstrates how to create a blank excel file. --- FAQ/How to Create an Empty Excel File.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/FAQ/How to Create an Empty Excel File.md b/FAQ/How to Create an Empty Excel File.md index e69de29..b017ac5 100644 --- a/FAQ/How to Create an Empty Excel File.md +++ b/FAQ/How to Create an Empty Excel File.md @@ -0,0 +1,6 @@ +# Create an Empty Excel File +Use an Empty String and Export to an Excel File. +```powershell +#Build an Excel file named: "file.xlsx" containing a worksheet: "MyWorksheet" +"" | Export-Excel -Path "C:\Test\file.xlsx -WorksheetName "MyWorksheet" +``` From 4a09fc3570a24cee23e57d561ce45f7a5cf9e7a2 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 10:25:14 -0800 Subject: [PATCH 064/140] Punctuation change --- FAQ/How to Create an Empty Excel File.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FAQ/How to Create an Empty Excel File.md b/FAQ/How to Create an Empty Excel File.md index b017ac5..04335d1 100644 --- a/FAQ/How to Create an Empty Excel File.md +++ b/FAQ/How to Create an Empty Excel File.md @@ -1,5 +1,5 @@ # Create an Empty Excel File -Use an Empty String and Export to an Excel File. +Use an empty string to export to an excel File. ```powershell #Build an Excel file named: "file.xlsx" containing a worksheet: "MyWorksheet" "" | Export-Excel -Path "C:\Test\file.xlsx -WorksheetName "MyWorksheet" From 5a444c620b9c93cff6fd6e54f2659adef67e5eb9 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 10:25:30 -0800 Subject: [PATCH 065/140] Punctuation change --- FAQ/How to Create an Empty Excel File.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FAQ/How to Create an Empty Excel File.md b/FAQ/How to Create an Empty Excel File.md index 04335d1..7293717 100644 --- a/FAQ/How to Create an Empty Excel File.md +++ b/FAQ/How to Create an Empty Excel File.md @@ -1,5 +1,5 @@ # Create an Empty Excel File -Use an empty string to export to an excel File. +Use an empty string to export to an excel file. ```powershell #Build an Excel file named: "file.xlsx" containing a worksheet: "MyWorksheet" "" | Export-Excel -Path "C:\Test\file.xlsx -WorksheetName "MyWorksheet" From 1e172cf21f4b0759b5277400bd8999ef73a2936b Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 12:16:41 -0800 Subject: [PATCH 066/140] Add Excel Pkg Data Img --- images/FAQ_Images/DataStructureExcelPkg.png | Bin 0 -> 3895 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/FAQ_Images/DataStructureExcelPkg.png diff --git a/images/FAQ_Images/DataStructureExcelPkg.png b/images/FAQ_Images/DataStructureExcelPkg.png new file mode 100644 index 0000000000000000000000000000000000000000..1709565e467039065582eab6997fcaa29f5ede0d GIT binary patch literal 3895 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 b7JPpYmqkm)QxWKAm+P#FrE#&5+s*#~e7_j+ literal 0 HcmV?d00001 From d71dd36d56268319df13efe4a24819d4984a79dd Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 12:17:39 -0800 Subject: [PATCH 067/140] First version of file, with Image. --- FAQ/How to Write to an Existing Excel File.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/FAQ/How to Write to an Existing Excel File.md b/FAQ/How to Write to an Existing Excel File.md index e69de29..15120e0 100644 --- a/FAQ/How to Write to an Existing Excel File.md +++ b/FAQ/How to Write to an Existing Excel File.md @@ -0,0 +1,19 @@ +# Write to an Existing Excel File +### Enumerate the Excel File +```powershell +$ExcelPkgFile = Open-ExcelPackage -Path "C:\Test\file.xlsx" +``` +Contents of file.xlsx: +![ExcelFileContents](/images/FAQ_Images/ExcelFileContents.png) +### Enumerate the Worksheet to View or Modify the Data +```powershell +$WorkSheet = $ExcelPkgFile.Workbook.Worksheets["sheet1"].Cells #open excel worksheet cells from worksheet "sheet1" +``` +Visual of Data Structure: +![DataStructureExcelPkg](/images/FAQ_Images/DataStructureExcelPkg.png) + +Modify a specific value by accessing row/col like a 2D Array: +```powershell +$WorkSheet[1,4].Value = "New Column Header" #Starts at index 1 not 0 +``` + From 6ebac7b6dc525ae6f77e22bf1c6cf917cdbb13f3 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 12:18:05 -0800 Subject: [PATCH 068/140] Add newlines --- FAQ/How to Write to an Existing Excel File.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FAQ/How to Write to an Existing Excel File.md b/FAQ/How to Write to an Existing Excel File.md index 15120e0..e8f6361 100644 --- a/FAQ/How to Write to an Existing Excel File.md +++ b/FAQ/How to Write to an Existing Excel File.md @@ -3,13 +3,13 @@ ```powershell $ExcelPkgFile = Open-ExcelPackage -Path "C:\Test\file.xlsx" ``` -Contents of file.xlsx: +Contents of file.xlsx: ![ExcelFileContents](/images/FAQ_Images/ExcelFileContents.png) ### Enumerate the Worksheet to View or Modify the Data ```powershell $WorkSheet = $ExcelPkgFile.Workbook.Worksheets["sheet1"].Cells #open excel worksheet cells from worksheet "sheet1" ``` -Visual of Data Structure: +Visual of Data Structure: ![DataStructureExcelPkg](/images/FAQ_Images/DataStructureExcelPkg.png) Modify a specific value by accessing row/col like a 2D Array: From 4d6193f5494d99f7a166f64e220619672db6f5c4 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 14:28:04 -0800 Subject: [PATCH 069/140] Complete Majority of Write to ExistingExcelFile md --- FAQ/How to Write to an Existing Excel File.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/FAQ/How to Write to an Existing Excel File.md b/FAQ/How to Write to an Existing Excel File.md index e8f6361..e4e5fcc 100644 --- a/FAQ/How to Write to an Existing Excel File.md +++ b/FAQ/How to Write to an Existing Excel File.md @@ -16,4 +16,16 @@ Modify a specific value by accessing row/col like a 2D Array: ```powershell $WorkSheet[1,4].Value = "New Column Header" #Starts at index 1 not 0 ``` +Contents of file.xlsx after modifying: +![ExcelFileContentsPostAdd](/images/FAQ_Images/ExcelFileContentsPostAdd.png) +Can also load a value at a specific index: +```powershell +$ValueAtIndex = $WorkSheet[2,1].Value #Loads the value at row 2, column A +``` +### Save File After Modifying +The changes will not display in the Excel file until Close-ExcelPackage is called. +```powershell +Close-ExcelPackage $ExcelPkgFile #close and save changes made to the Excel file. +``` +**Note**: If the file is currently in use, Close-ExcelPackage will return an error and will not save the information. From 8b3bf4f14fb38cda9864da6910f9bdd1efde6579 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 14:33:48 -0800 Subject: [PATCH 070/140] Added Debug image showing var contents --- images/FAQ_Images/ExcelFileContentsPostAdd.png | Bin 0 -> 3818 bytes images/FAQ_Images/ValueAtIndexData.png | Bin 0 -> 1445 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/FAQ_Images/ExcelFileContentsPostAdd.png create mode 100644 images/FAQ_Images/ValueAtIndexData.png diff --git a/images/FAQ_Images/ExcelFileContentsPostAdd.png b/images/FAQ_Images/ExcelFileContentsPostAdd.png new file mode 100644 index 0000000000000000000000000000000000000000..83369fcbd88eb744d7964267adad3614aeb3c763 GIT binary patch literal 3818 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 Ul5@wLfesGR(m<+Ls9HY#4}hI^`2YX_ literal 0 HcmV?d00001 diff --git a/images/FAQ_Images/ValueAtIndexData.png b/images/FAQ_Images/ValueAtIndexData.png new file mode 100644 index 0000000000000000000000000000000000000000..2e9f4ff07bcf4a9206ab2991d9134a599084a89c GIT binary patch literal 1445 zcmV;W1zP%vP)?-n00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1v*JYK~!i%?U`Rl zTUQ*%k7Ey0jK-QN%^DlqG&h=p8S5^RNT8NLHiy*;!pt7rr5hIXA(Zw(`#60lbUrB5 zhZ2M}85B}&*hV00H=L1jS(#xb8dp zIluG$onJKXxJHL^WEJnQbB^pG7qjdm7qjdm7qjdm7qjf+4KZu!ZS6F&>kQy}oWhVx z=)bC9j)THqX+8KL#@cUh)$+_ZH0@1Ix6LxM`P@i5XJ$T%>{|P|Yvs(?PC0jbd;2|s z0h?~<@e@ayl+2fg-D766!t7fr3r}}K*ti~-wIz?;!MFOj4QmtOUYo-)xy-D6py<3M zq#2VyUWOfSF&>%o+e-;0q%mf_CG`AA*Dm3idnK*Bl9-W(ciDLp#@hY{s}8WKJ% zgqx{eMosaoe@a_<0fpVEVH<~B@EP;jyl$tr!3qR4qU`>5q~v!$(s%6=Qgh!H_QZ>>v}rT(j)wd1^1DR zIHF?nXbgmMo_qs)SCt)N@L=?EPk4KhLBdn=g}zoahJi+Ds5r2)-8I- zv;3$5@2U)HwskYs~yA*E2)OJYH)FAP}Ut+M>$K{PAY~h(Fpgfuw!wA;C&1xwN zImjxGur3(^W0JKG2T62B%}I5&05jWJU7)VaRIl4n94%v4n}L)_9t1~9uWPFZ*m0AX zOJ&=4-E!{h8fmNYcA)3a%c<FP%QgQEDecr>w`FE0ht9f}>(TXA9}yBg*N z$(*1(YVKq{u~t?BB?Et@o~lZGwv?~cd`xaqKzZ@x%=*Z(0L0kRd*q=R6Mz1q@MImV zEk);-)l|Un=E;1X#AX%b0sF-O`qY|Q9I&53g~g1$7<(xdoKQkRXg2dHRY{9D66H$W zhG#)qkQHx{6fI%&$NnvyK@H*(1Vf>!K@hYN2QDH=dQ>Yn5+gB9I5+AOLArq?dqGAT za*-bi6MsEMSVKZdWQw+NdVLE-Rrr8CM!{>BHWmThHSyKP;Iv-FbtB|bC}PvrjqYxL z96z_Q_*Z|Fc*N@urrxJ{nDoMhRT0UbVc%qtCG$9KAt-thRranX`;qB;^f?Q$8H7C} zpP(7)!NmTID$nC&h|6~rd^)EhRpO~drbXBnVUQXb!v6HX8PbsE@A^=uoq7IM+7ckg ze@X6tG1*7D{Vd1-mt4%Uk6g^Mk6g^M4TSyyTqi;Rk00000NkvXXu0mjfv|F@o literal 0 HcmV?d00001 From 86a7865fb2ffb1fa9f8a5db43409e90c8d324e4a Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 14:34:17 -0800 Subject: [PATCH 071/140] Add multiple images. --- FAQ/How to Write to an Existing Excel File.md | 1 + 1 file changed, 1 insertion(+) diff --git a/FAQ/How to Write to an Existing Excel File.md b/FAQ/How to Write to an Existing Excel File.md index e4e5fcc..9a9839a 100644 --- a/FAQ/How to Write to an Existing Excel File.md +++ b/FAQ/How to Write to an Existing Excel File.md @@ -22,6 +22,7 @@ Can also load a value at a specific index: ```powershell $ValueAtIndex = $WorkSheet[2,1].Value #Loads the value at row 2, column A ``` +```$ValueAtIndex``` now contains: ![ValueAtIndexData](/images/FAQ_Images/ValueAtIndexData.png) ### Save File After Modifying The changes will not display in the Excel file until Close-ExcelPackage is called. ```powershell From 1c8f8d2a3db34268b3da6439a6efcf64ebfb67dd Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 14:41:37 -0800 Subject: [PATCH 072/140] Update image to include row/col data num --- .../FAQ_Images/ExcelFileContentsPostAdd.png | Bin 3818 -> 5251 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/FAQ_Images/ExcelFileContentsPostAdd.png b/images/FAQ_Images/ExcelFileContentsPostAdd.png index 83369fcbd88eb744d7964267adad3614aeb3c763..2e26d0cf45b9a784c46b41c906b723fd5bbe07ee 100644 GIT binary patch literal 5251 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 E0>%^sg#Z8m literal 3818 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 Ul5@wLfesGR(m<+Ls9HY#4}hI^`2YX_ From 0d4a32e266830f3211e312238f692b77af2685dc Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 14:42:44 -0800 Subject: [PATCH 073/140] Change phrasing to show better MD style Added additional headings to read more easily. --- FAQ/How to Write to an Existing Excel File.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/FAQ/How to Write to an Existing Excel File.md b/FAQ/How to Write to an Existing Excel File.md index 9a9839a..3aed143 100644 --- a/FAQ/How to Write to an Existing Excel File.md +++ b/FAQ/How to Write to an Existing Excel File.md @@ -12,13 +12,14 @@ $WorkSheet = $ExcelPkgFile.Workbook.Worksheets["sheet1"].Cells #open excel works Visual of Data Structure: ![DataStructureExcelPkg](/images/FAQ_Images/DataStructureExcelPkg.png) -Modify a specific value by accessing row/col like a 2D Array: +### Modify a Specific Value in a File +Values can be accessed by row, col. Similar to a 2D array. ```powershell $WorkSheet[1,4].Value = "New Column Header" #Starts at index 1 not 0 ``` Contents of file.xlsx after modifying: -![ExcelFileContentsPostAdd](/images/FAQ_Images/ExcelFileContentsPostAdd.png) -Can also load a value at a specific index: +![ExcelFileContentsPostAdd](/images/FAQ_Images/ExcelFileContentsPostAdd.png) +### Load Value at Specific Index ```powershell $ValueAtIndex = $WorkSheet[2,1].Value #Loads the value at row 2, column A ``` From 565765933149e3171b01ed3f76097b014b2d3959 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Fri, 26 Nov 2021 14:53:21 -0800 Subject: [PATCH 074/140] Add additional dbg info, Doc complete. Changed variable name in example code, added additional info to Data structure explanation. Final proofread for punctuation and style. Document complete. --- FAQ/How to Write to an Existing Excel File.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/FAQ/How to Write to an Existing Excel File.md b/FAQ/How to Write to an Existing Excel File.md index 3aed143..c5d3b30 100644 --- a/FAQ/How to Write to an Existing Excel File.md +++ b/FAQ/How to Write to an Existing Excel File.md @@ -1,19 +1,19 @@ # Write to an Existing Excel File ### Enumerate the Excel File ```powershell -$ExcelPkgFile = Open-ExcelPackage -Path "C:\Test\file.xlsx" +$ExcelPkg = Open-ExcelPackage -Path "C:\Test\file.xlsx" ``` Contents of file.xlsx: ![ExcelFileContents](/images/FAQ_Images/ExcelFileContents.png) ### Enumerate the Worksheet to View or Modify the Data ```powershell -$WorkSheet = $ExcelPkgFile.Workbook.Worksheets["sheet1"].Cells #open excel worksheet cells from worksheet "sheet1" +$WorkSheet = $ExcelPkg.Workbook.Worksheets["sheet1"].Cells #open excel worksheet cells from worksheet "sheet1" ``` -Visual of Data Structure: -![DataStructureExcelPkg](/images/FAQ_Images/DataStructureExcelPkg.png) - +Visual of data structure: +![DataStructureExcelPkg](/images/FAQ_Images/DataStructureExcelPkg.png) +A1 contains "someHeader", A2 contains "data1" etc. ### Modify a Specific Value in a File -Values can be accessed by row, col. Similar to a 2D array. +Values can be accessed by row, column. Similar to a 2D array. ```powershell $WorkSheet[1,4].Value = "New Column Header" #Starts at index 1 not 0 ``` @@ -27,7 +27,7 @@ $ValueAtIndex = $WorkSheet[2,1].Value #Loads the value at row 2, column A ### Save File After Modifying The changes will not display in the Excel file until Close-ExcelPackage is called. ```powershell -Close-ExcelPackage $ExcelPkgFile #close and save changes made to the Excel file. +Close-ExcelPackage $ExcelPkg #close and save changes made to the Excel file. ``` **Note**: If the file is currently in use, Close-ExcelPackage will return an error and will not save the information. From 56e1704e7e8146b67c4dea09e7c01105c25efc69 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Sun, 28 Nov 2021 11:25:21 -0800 Subject: [PATCH 075/140] Added missing " || improved readability. --- FAQ/How to Create an Empty Excel File.md | 2 +- FAQ/How to Read an Existing Excel File.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/FAQ/How to Create an Empty Excel File.md b/FAQ/How to Create an Empty Excel File.md index 7293717..33b63ce 100644 --- a/FAQ/How to Create an Empty Excel File.md +++ b/FAQ/How to Create an Empty Excel File.md @@ -2,5 +2,5 @@ Use an empty string to export to an excel file. ```powershell #Build an Excel file named: "file.xlsx" containing a worksheet: "MyWorksheet" -"" | Export-Excel -Path "C:\Test\file.xlsx -WorksheetName "MyWorksheet" +"" | Export-Excel -Path "C:\Test\file.xlsx" -WorksheetName "MyWorksheet" ``` diff --git a/FAQ/How to Read an Existing Excel File.md b/FAQ/How to Read an Existing Excel File.md index 30ad946..2ea6e08 100644 --- a/FAQ/How to Read an Existing Excel File.md +++ b/FAQ/How to Read an Existing Excel File.md @@ -30,7 +30,9 @@ Sometimes mapping to a Hashtable is more convenient to have access to common Has ```powershell $HashTable = @{} $SpecificRow= $ExcelFile[2] -$SpecificRow.psobject.properties | ForEach-Object {$HashTable[$_.Name] = $_.Value} +$SpecificRow.psobject.properties | ForEach-Object { + $HashTable[$_.Name] = $_.Value +} ``` To then iterate through the enumerated Hashtable: ```powershell From 5700989321d1fc3abd3cc81a747eea3ba1b366f4 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Sun, 28 Nov 2021 11:36:37 -0800 Subject: [PATCH 076/140] Explain functionality of Open/Close-ExcelPackage --- FAQ/How to Write to an Existing Excel File.md | 1 + 1 file changed, 1 insertion(+) diff --git a/FAQ/How to Write to an Existing Excel File.md b/FAQ/How to Write to an Existing Excel File.md index c5d3b30..ce796dd 100644 --- a/FAQ/How to Write to an Existing Excel File.md +++ b/FAQ/How to Write to an Existing Excel File.md @@ -1,5 +1,6 @@ # Write to an Existing Excel File ### Enumerate the Excel File +The cmdlets ```Open-ExcelPackage``` and ```Close-ExcelPackage``` allow for direct modification to Excel file contents. ```powershell $ExcelPkg = Open-ExcelPackage -Path "C:\Test\file.xlsx" ``` From 229b60b25d80557454f134089241b87db26b2d27 Mon Sep 17 00:00:00 2001 From: Davis Henckel <51898571+DavisHenckel@users.noreply.github.com> Date: Sun, 28 Nov 2021 20:03:07 -0800 Subject: [PATCH 077/140] Remove Unnecessary Import & Add Header Removed unnecessary import-module statement. Added a header to match the styling of other documents. --- FAQ/How to Read an Existing Excel File.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/FAQ/How to Read an Existing Excel File.md b/FAQ/How to Read an Existing Excel File.md index 2ea6e08..bb869ca 100644 --- a/FAQ/How to Read an Existing Excel File.md +++ b/FAQ/How to Read an Existing Excel File.md @@ -1,8 +1,7 @@ # How to Read an Existing Excel File - +## Enumerate the Excel File Contents ```powershell -Import-Module ImportExcel -#Loads the Excel file into a PSCustomObject +#Load the Excel file into a PSCustomObject $ExcelFile = Import-Excel "C:\Test\file.xlsx" -WorksheetName "Sheet1" ``` From 7e8416d67c8dceacd060865d4c1c27d65f401f95 Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 30 Nov 2021 15:49:07 -0500 Subject: [PATCH 078/140] Bump version and update change log --- ImportExcel.psd1 | 2 +- changelog.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index 59e1612..7d7a2be 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.4.0' + ModuleVersion = '7.4.1' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' diff --git a/changelog.md b/changelog.md index e504eda..06b93ae 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,10 @@ +# v7.4.1 + +- Implements: https://github.com/dfinke/ImportExcel/issues/1111 +- Refactored ReZip into separate function +- Deletes temp folder after rezipping +- Added -ReZip to `Close-ExcelPackage` + # v7.4.0 - Thank you to [Max Goczall](https://github.com/muschebubusche) for this contribution! From aa1b0427671c97ae4c135efd9363ad6b0e7c7e98 Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 30 Nov 2021 15:50:11 -0500 Subject: [PATCH 079/140] Add -ReZip to Close-ExcelPackage like in Export-Excel #1111 --- Private/Invoke-ExcelReZipFile.ps1 | 25 ++ Public/Close-ExcelPackage.ps1 | 31 +- Public/Export-Excel.ps1 | 499 +++++++++++++++--------------- 3 files changed, 289 insertions(+), 266 deletions(-) create mode 100644 Private/Invoke-ExcelReZipFile.ps1 diff --git a/Private/Invoke-ExcelReZipFile.ps1 b/Private/Invoke-ExcelReZipFile.ps1 new file mode 100644 index 0000000..0c94968 --- /dev/null +++ b/Private/Invoke-ExcelReZipFile.ps1 @@ -0,0 +1,25 @@ +function Invoke-ExcelReZipFile { + <# + #> + param( + [Parameter(Mandatory)] + [OfficeOpenXml.ExcelPackage]$ExcelPackage + ) + + Write-Verbose -Message "Re-Zipping $($ExcelPackage.file) using .NET ZIP library" + try { + Add-Type -AssemblyName 'System.IO.Compression.Filesystem' -ErrorAction stop + } + catch { + Write-Error "The -ReZip parameter requires .NET Framework 4.5 or later to be installed. Recommend to install Powershell v4+" + continue + } + try { + $TempZipPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName()) + $null = [io.compression.zipfile]::ExtractToDirectory($ExcelPackage.File, $TempZipPath) + Remove-Item $ExcelPackage.File -Force + $null = [io.compression.zipfile]::CreateFromDirectory($TempZipPath, $ExcelPackage.File) + Remove-Item $TempZipPath -Recurse -Force + } + catch { throw "Error resizipping $path : $_" } +} \ No newline at end of file diff --git a/Public/Close-ExcelPackage.ps1 b/Public/Close-ExcelPackage.ps1 index c2d9ad4..ee64bc0 100644 --- a/Public/Close-ExcelPackage.ps1 +++ b/Public/Close-ExcelPackage.ps1 @@ -1,33 +1,38 @@ function Close-ExcelPackage { [CmdLetBinding()] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword","")] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] param ( - [parameter(Mandatory=$true, ValueFromPipeline=$true)] + [parameter(Mandatory = $true, ValueFromPipeline = $true)] [OfficeOpenXml.ExcelPackage]$ExcelPackage, - [switch]$Show, + [Switch]$Show, [Switch]$NoSave, $SaveAs, [ValidateNotNullOrEmpty()] [String]$Password, - [switch]$Calculate + [Switch]$Calculate, + [Switch]$ReZip ) - if ( $NoSave) {$ExcelPackage.Dispose()} + + if ( $NoSave) { $ExcelPackage.Dispose() } else { if ($Calculate) { - try { [OfficeOpenXml.CalculationExtension]::Calculate($ExcelPackage.Workbook) } - catch { Write-Warning "One or more errors occured while calculating, save will continue, but there may be errors in the workbook."} + try { [OfficeOpenXml.CalculationExtension]::Calculate($ExcelPackage.Workbook) } + catch { Write-Warning "One or more errors occured while calculating, save will continue, but there may be errors in the workbook." } } if ($SaveAs) { $SaveAs = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($SaveAs) - if ($Password) {$ExcelPackage.SaveAs( $SaveAs, $Password ) } - else {$ExcelPackage.SaveAs( $SaveAs)} + if ($Password) { $ExcelPackage.SaveAs( $SaveAs, $Password ) } + else { $ExcelPackage.SaveAs( $SaveAs) } } - else { - if ($Password) {$ExcelPackage.Save($Password) } - else {$ExcelPackage.Save() } + else { + if ($Password) { $ExcelPackage.Save($Password) } + else { $ExcelPackage.Save() } $SaveAs = $ExcelPackage.File.FullName } + if ($ReZip) { + Invoke-ExcelReZipFile -ExcelPackage $ExcelPackage + } $ExcelPackage.Dispose() - if ($Show) {Start-Process -FilePath $SaveAs } + if ($Show) { Start-Process -FilePath $SaveAs } } } diff --git a/Public/Export-Excel.ps1 b/Public/Export-Excel.ps1 index 40e41f2..f11d1e5 100644 --- a/Public/Export-Excel.ps1 +++ b/Public/Export-Excel.ps1 @@ -22,7 +22,7 @@ [Switch]$TitleBold, [Int]$TitleSize = 22, $TitleBackgroundColor, - [parameter(DontShow=$true)] + [parameter(DontShow = $true)] [Switch]$IncludePivotTable, [String]$PivotTableName, [String[]]$PivotRows, @@ -48,14 +48,14 @@ [Switch]$BoldTopRow, [Switch]$NoHeader, [ValidateScript( { - if (-not $_) { throw 'RangeName is null or empty.' } - elseif ($_[0] -notmatch '[a-z]') { throw 'RangeName starts with an invalid character.' } + if (-not $_) { throw 'RangeName is null or empty.' } + elseif ($_[0] -notmatch '[a-z]') { throw 'RangeName starts with an invalid character.' } else { $true } - })] + })] [String]$RangeName, [Alias('Table')] $TableName, - [OfficeOpenXml.Table.TableStyles]$TableStyle = [OfficeOpenXml.Table.TableStyles]::Medium6, + [OfficeOpenXml.Table.TableStyles]$TableStyle = [OfficeOpenXml.Table.TableStyles]::Medium6, [Switch]$Barchart, [Switch]$PieChart, [Switch]$LineChart , @@ -88,7 +88,7 @@ [Switch]$Now, [Switch]$ReturnRange, #By default PivotTables have Totals for each Row (on the right) and for each column at the bottom. This allows just one or neither to be selected. - [ValidateSet("Both","Columns","Rows","None")] + [ValidateSet("Both", "Columns", "Rows", "None")] [String]$PivotTotals = "Both", #Included for compatibility - equivalent to -PivotTotals "None" [Switch]$NoTotalsInPivot, @@ -98,13 +98,13 @@ begin { $numberRegex = [Regex]'\d' $isDataTypeValueType = $false - if ($NoClobber) {Write-Warning -Message "-NoClobber parameter is no longer used" } + if ($NoClobber) { Write-Warning -Message "-NoClobber parameter is no longer used" } #Open the file, get the worksheet, and decide where in the sheet we are writing, and if there is a number format to apply. - try { + try { $script:Header = $null - if ($Append -and $ClearSheet) {throw "You can't use -Append AND -ClearSheet." ; return} + if ($Append -and $ClearSheet) { throw "You can't use -Append AND -ClearSheet." ; return } #To force -Now not to format as a table, allow $false in -TableName to be "No table" - $TableName = if ($null -eq $TableName -or ($TableName -is [bool] -and $false -eq $TableName)) { $null } else {[String]$TableName} + $TableName = if ($null -eq $TableName -or ($TableName -is [bool] -and $false -eq $TableName)) { $null } else { [String]$TableName } if ($Now -or (-not $Path -and -not $ExcelPackage) ) { if (-not $PSBoundParameters.ContainsKey("Path")) { $Path = [System.IO.Path]::GetTempFileName() -replace '\.tmp', '.xlsx' } if (-not $PSBoundParameters.ContainsKey("Show")) { $Show = $true } @@ -120,59 +120,59 @@ $pkg = $ExcelPackage $Path = $pkg.File } - Else { $pkg = Open-ExcelPackage -Path $Path -Create -KillExcel:$KillExcel -Password:$Password} + Else { $pkg = Open-ExcelPackage -Path $Path -Create -KillExcel:$KillExcel -Password:$Password } } - catch {throw "Could not open Excel Package $path"} - try { - $params = @{WorksheetName=$WorksheetName} - foreach ($p in @("ClearSheet", "MoveToStart", "MoveToEnd", "MoveBefore", "MoveAfter", "Activate")) {if ($PSBoundParameters[$p]) {$params[$p] = $PSBoundParameters[$p]}} + catch { throw "Could not open Excel Package $path" } + try { + $params = @{WorksheetName = $WorksheetName } + foreach ($p in @("ClearSheet", "MoveToStart", "MoveToEnd", "MoveBefore", "MoveAfter", "Activate")) { if ($PSBoundParameters[$p]) { $params[$p] = $PSBoundParameters[$p] } } $ws = $pkg | Add-Worksheet @params if ($ws.Name -ne $WorksheetName) { Write-Warning -Message "The Worksheet name has been changed from $WorksheetName to $($ws.Name), this may cause errors later." $WorksheetName = $ws.Name } } - catch {throw "Could not get worksheet $WorksheetName"} - try { + catch { throw "Could not get worksheet $WorksheetName" } + try { if ($Append -and $ws.Dimension) { #if there is a title or anything else above the header row, append needs to be combined wih a suitable startrow parameter $headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow #using a slightly odd syntax otherwise header ends up as a 2D array - $ws.Cells[$headerRange].Value | ForEach-Object -Begin {$Script:header = @()} -Process {$Script:header += $_ } + $ws.Cells[$headerRange].Value | ForEach-Object -Begin { $Script:header = @() } -Process { $Script:header += $_ } $NoHeader = $true #if we did not get AutoNameRange, but headers have ranges of the same name make autoNameRange True, otherwise make it false if (-not $AutoNameRange) { - $AutoNameRange = $true ; foreach ($h in $header) {if ($ws.names.name -notcontains $h) {$AutoNameRange = $false} } + $AutoNameRange = $true ; foreach ($h in $header) { if ($ws.names.name -notcontains $h) { $AutoNameRange = $false } } } #if we did not get a Rangename but there is a Range which covers the active part of the sheet, set Rangename to that. - if (-not $RangeName -and $ws.names.where({$_.name[0] -match '[a-z]'})) { + if (-not $RangeName -and $ws.names.where({ $_.name[0] -match '[a-z]' })) { $theRange = $ws.names.where({ - ($_.Name[0] -match '[a-z]' ) -and - ($_.Start.Row -eq $StartRow) -and - ($_.Start.Column -eq $StartColumn) -and - ($_.End.Row -eq $ws.Dimension.End.Row) -and - ($_.End.Column -eq $ws.Dimension.End.column) } , 'First', 1) - if ($theRange) {$rangename = $theRange.name} + ($_.Name[0] -match '[a-z]' ) -and + ($_.Start.Row -eq $StartRow) -and + ($_.Start.Column -eq $StartColumn) -and + ($_.End.Row -eq $ws.Dimension.End.Row) -and + ($_.End.Column -eq $ws.Dimension.End.column) } , 'First', 1) + if ($theRange) { $rangename = $theRange.name } } #if we did not get a table name but there is a table which covers the active part of the sheet, set table name to that, and don't do anything with autofilter - $existingTable = $ws.Tables.Where({$_.address.address -eq $ws.dimension.address},'First', 1) + $existingTable = $ws.Tables.Where({ $_.address.address -eq $ws.dimension.address }, 'First', 1) if ($null -eq $TableName -and $existingTable) { - $TableName = $existingTable.Name - $TableStyle = $existingTable.StyleName -replace "^TableStyle","" + $TableName = $existingTable.Name + $TableStyle = $existingTable.StyleName -replace "^TableStyle", "" $AutoFilter = $false } #if we did not get $autofilter but a filter range is set and it covers the right area, set autofilter to true elseif (-not $AutoFilter -and $ws.Names['_xlnm._FilterDatabase']) { - if ( ($ws.Names['_xlnm._FilterDatabase'].Start.Row -eq $StartRow) -and + if ( ($ws.Names['_xlnm._FilterDatabase'].Start.Row -eq $StartRow) -and ($ws.Names['_xlnm._FilterDatabase'].Start.Column -eq $StartColumn) -and - ($ws.Names['_xlnm._FilterDatabase'].End.Row -eq $ws.Dimension.End.Row) -and - ($ws.Names['_xlnm._FilterDatabase'].End.Column -eq $ws.Dimension.End.Column) ) {$AutoFilter = $true} + ($ws.Names['_xlnm._FilterDatabase'].End.Row -eq $ws.Dimension.End.Row) -and + ($ws.Names['_xlnm._FilterDatabase'].End.Column -eq $ws.Dimension.End.Column) ) { $AutoFilter = $true } } $row = $ws.Dimension.End.Row Write-Debug -Message ("Appending: headers are " + ($script:Header -join ", ") + " Start row is $row") - if ($Title) {Write-Warning -Message "-Title Parameter is ignored when appending."} + if ($Title) { Write-Warning -Message "-Title Parameter is ignored when appending." } } elseif ($Title) { #Can only add a title if not appending! @@ -180,41 +180,41 @@ $ws.Cells[$row, $StartColumn].Value = $Title $ws.Cells[$row, $StartColumn].Style.Font.Size = $TitleSize - if ($PSBoundParameters.ContainsKey("TitleBold")) { + if ($PSBoundParameters.ContainsKey("TitleBold")) { #Set title to Bold face font if -TitleBold was specified. #Otherwise the default will be unbolded. $ws.Cells[$row, $StartColumn].Style.Font.Bold = [boolean]$TitleBold } if ($TitleBackgroundColor ) { - if ($TitleBackgroundColor -is [string]) {$TitleBackgroundColor = [System.Drawing.Color]::$TitleBackgroundColor } + if ($TitleBackgroundColor -is [string]) { $TitleBackgroundColor = [System.Drawing.Color]::$TitleBackgroundColor } $ws.Cells[$row, $StartColumn].Style.Fill.PatternType = $TitleFillPattern $ws.Cells[$row, $StartColumn].Style.Fill.BackgroundColor.SetColor($TitleBackgroundColor) } $row ++ ; $startRow ++ } - else { $row = $StartRow } + else { $row = $StartRow } $ColumnIndex = $StartColumn $Numberformat = Expand-NumberFormat -NumberFormat $Numberformat if ((-not $ws.Dimension) -and ($Numberformat -ne $ws.Cells.Style.Numberformat.Format)) { - $ws.Cells.Style.Numberformat.Format = $Numberformat - $setNumformat = $false + $ws.Cells.Style.Numberformat.Format = $Numberformat + $setNumformat = $false } - else { $setNumformat = ($Numberformat -ne $ws.Cells.Style.Numberformat.Format) } + else { $setNumformat = ($Numberformat -ne $ws.Cells.Style.Numberformat.Format) } } - catch {throw "Failed preparing to export to worksheet '$WorksheetName' to '$Path': $_"} + catch { throw "Failed preparing to export to worksheet '$WorksheetName' to '$Path': $_" } #region Special case -inputobject passed a dataTable object <# If inputObject was passed via the pipeline it won't be visible until the process block, we will only see it here if it was passed as a parameter if it is a data table don't do foreach on it (slow) - put the whole table in and set dates on date columns, set things up for the end block, and skip the process block #> - if ($InputObject -is [System.Data.DataTable]) { + if ($InputObject -is [System.Data.DataTable]) { if ($Append -and $ws.dimension) { $row ++ - $null = $ws.Cells[$row,$StartColumn].LoadFromDataTable($InputObject, $false ) - if ($TableName -or $PSBoundParameters.ContainsKey('TableStyle')) { + $null = $ws.Cells[$row, $StartColumn].LoadFromDataTable($InputObject, $false ) + if ($TableName -or $PSBoundParameters.ContainsKey('TableStyle')) { Add-ExcelTable -Range $ws.Cells[$ws.Dimension] -TableName $TableName -TableStyle $TableStyle } } - else { + else { #Change TableName if $TableName is non-empty; don't leave caller with a renamed table! $orginalTableName = $InputObject.TableName if ($PSBoundParameters.ContainsKey("TableName")) { @@ -226,157 +226,160 @@ } #Insert as a table, if Tablestyle didn't arrive as a default, or $TableName non-null - even if empty if ($null -ne $TableName -or $PSBoundParameters.ContainsKey("TableStyle")) { - $null = $ws.Cells[$row,$StartColumn].LoadFromDataTable($InputObject, (-not $noHeader),$TableStyle ) + $null = $ws.Cells[$row, $StartColumn].LoadFromDataTable($InputObject, (-not $noHeader), $TableStyle ) # Workaround for EPPlus not marking the empty row on an empty table as dummy row. if ($InputObject.Rows.Count -eq 0) { ($ws.Tables | Select-Object -Last 1).TableXml.table.SetAttribute('insertRow', 1) } } else { - $null = $ws.Cells[$row,$StartColumn].LoadFromDataTable($InputObject, (-not $noHeader) ) + $null = $ws.Cells[$row, $StartColumn].LoadFromDataTable($InputObject, (-not $noHeader) ) } $InputObject.TableName = $orginalTableName } - foreach ($c in $InputObject.Columns.where({$_.datatype -eq [datetime]})) { + foreach ($c in $InputObject.Columns.where({ $_.datatype -eq [datetime] })) { Set-ExcelColumn -Worksheet $ws -Column ($c.Ordinal + $StartColumn) -NumberFormat 'Date-Time' } - foreach ($c in $InputObject.Columns.where({$_.datatype -eq [timespan]})) { + foreach ($c in $InputObject.Columns.where({ $_.datatype -eq [timespan] })) { Set-ExcelColumn -Worksheet $ws -Column ($c.Ordinal + $StartColumn) -NumberFormat '[h]:mm:ss' } - $ColumnIndex += $InputObject.Columns.Count - 1 - if ($noHeader) {$row += $InputObject.Rows.Count -1 } - else {$row += $InputObject.Rows.Count } + $ColumnIndex += $InputObject.Columns.Count - 1 + if ($noHeader) { $row += $InputObject.Rows.Count - 1 } + else { $row += $InputObject.Rows.Count } $null = $PSBoundParameters.Remove('InputObject') $firstTimeThru = $false } #endregion - else {$firstTimeThru = $true} + else { $firstTimeThru = $true } } - process { if ($PSBoundParameters.ContainsKey("InputObject")) { - try { - if ($null -eq $InputObject) {$row += 1} - foreach ($TargetData in $InputObject) { - if ($firstTimeThru) { - $firstTimeThru = $false - $isDataTypeValueType = ($null -eq $TargetData) -or ($TargetData.GetType().name -match 'string|timespan|datetime|bool|byte|char|decimal|double|float|int|long|sbyte|short|uint|ulong|ushort|URI|ExcelHyperLink') - if ($isDataTypeValueType ) { - $script:Header = @(".") # dummy value to make sure we go through the "for each name in $header" - if (-not $Append) {$row -= 1} # By default row will be 1, it is incremented before inserting values (so it ends pointing at final row.); si first data row is 2 - move back up 1 if there is no header . + process { + if ($PSBoundParameters.ContainsKey("InputObject")) { + try { + if ($null -eq $InputObject) { $row += 1 } + foreach ($TargetData in $InputObject) { + if ($firstTimeThru) { + $firstTimeThru = $false + $isDataTypeValueType = ($null -eq $TargetData) -or ($TargetData.GetType().name -match 'string|timespan|datetime|bool|byte|char|decimal|double|float|int|long|sbyte|short|uint|ulong|ushort|URI|ExcelHyperLink') + if ($isDataTypeValueType ) { + $script:Header = @(".") # dummy value to make sure we go through the "for each name in $header" + if (-not $Append) { $row -= 1 } # By default row will be 1, it is incremented before inserting values (so it ends pointing at final row.); si first data row is 2 - move back up 1 if there is no header . + } + if ($null -ne $TargetData) { Write-Debug "DataTypeName is '$($TargetData.GetType().name)' isDataTypeValueType '$isDataTypeValueType'" } } - if ($null -ne $TargetData) {Write-Debug "DataTypeName is '$($TargetData.GetType().name)' isDataTypeValueType '$isDataTypeValueType'" } - } - #region Add headers - if we are appending, or we have been through here once already we will have the headers - if (-not $script:Header) { - if ($DisplayPropertySet -and $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) { - $script:Header = $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( {$_ -notin $ExcludeProperty}) - } - else { - if ($NoAliasOrScriptPropeties) {$propType = "Property"} else {$propType = "*"} - $script:Header = $TargetData.PSObject.Properties.where( {$_.MemberType -like $propType}).Name - } - foreach ($exclusion in $ExcludeProperty) {$script:Header = $script:Header -notlike $exclusion} - if ($NoHeader) { - # Don't push the headers to the spreadsheet - $row -= 1 - } - else { - $ColumnIndex = $StartColumn - foreach ($Name in $script:Header) { - $ws.Cells[$row, $ColumnIndex].Value = $Name - Write-Verbose "Cell '$row`:$ColumnIndex' add header '$Name'" - $ColumnIndex += 1 + #region Add headers - if we are appending, or we have been through here once already we will have the headers + if (-not $script:Header) { + if ($DisplayPropertySet -and $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) { + $script:Header = $TargetData.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( { $_ -notin $ExcludeProperty }) + } + else { + if ($NoAliasOrScriptPropeties) { $propType = "Property" } else { $propType = "*" } + $script:Header = $TargetData.PSObject.Properties.where( { $_.MemberType -like $propType }).Name + } + foreach ($exclusion in $ExcludeProperty) { $script:Header = $script:Header -notlike $exclusion } + if ($NoHeader) { + # Don't push the headers to the spreadsheet + $row -= 1 + } + else { + $ColumnIndex = $StartColumn + foreach ($Name in $script:Header) { + $ws.Cells[$row, $ColumnIndex].Value = $Name + Write-Verbose "Cell '$row`:$ColumnIndex' add header '$Name'" + $ColumnIndex += 1 + } } } - } - #endregion - #region Add non header values - $row += 1 - $ColumnIndex = $StartColumn - <# + #endregion + #region Add non header values + $row += 1 + $ColumnIndex = $StartColumn + <# For each item in the header OR for the Data item if this is a simple Type or data table : If it is a date insert with one of Excel's built in formats - recognized as "Date and time to be localized" if it is a timespan insert with a built in format for elapsed hours, minutes and seconds if its any other numeric insert as is , setting format if need be. Preserve URI, Insert a data table, convert non string objects to string. For strings, check for fomula, URI or Number, before inserting as a string (ignore nulls) #> - foreach ($Name in $script:Header) { - if ($isDataTypeValueType) {$v = $TargetData} - else {$v = $TargetData.$Name} - try { - if ($v -is [DateTime]) { - $ws.Cells[$row, $ColumnIndex].Value = $v - $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = 'm/d/yy h:mm' # This is not a custom format, but a preset recognized as date and localized. - } - elseif ($v -is [TimeSpan]) { - $ws.Cells[$row, $ColumnIndex].Value = $v - $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = '[h]:mm:ss' - } - elseif ($v -is [System.ValueType]) { - $ws.Cells[$row, $ColumnIndex].Value = $v - if ($setNumformat) {$ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = $Numberformat } - } - elseif ($v -is [uri] ) { - $ws.Cells[$row, $ColumnIndex].HyperLink = $v - $ws.Cells[$row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue) - $ws.Cells[$row, $ColumnIndex].Style.Font.UnderLine = $true - } - elseif ($v -isnot [String] ) { #Other objects or null. - if ($null -ne $v) { $ws.Cells[$row, $ColumnIndex].Value = $v.toString()} - } - elseif ($v[0] -eq '=') { - $ws.Cells[$row, $ColumnIndex].Formula = ($v -replace '^=','') - if ($setNumformat) {$ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = $Numberformat } - } - elseif ( [System.Uri]::IsWellFormedUriString($v , [System.UriKind]::Absolute) ) { - if ($v -match "^xl://internal/") { - $referenceAddress = $v -replace "^xl://internal/" , "" - $display = $referenceAddress -replace "!A1$" , "" - $h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display - $ws.Cells[$row, $ColumnIndex].HyperLink = $h + foreach ($Name in $script:Header) { + if ($isDataTypeValueType) { $v = $TargetData } + else { $v = $TargetData.$Name } + try { + if ($v -is [DateTime]) { + $ws.Cells[$row, $ColumnIndex].Value = $v + $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = 'm/d/yy h:mm' # This is not a custom format, but a preset recognized as date and localized. } - else {$ws.Cells[$row, $ColumnIndex].HyperLink = $v } #$ws.Cells[$row, $ColumnIndex].Value = $v.AbsoluteUri - $ws.Cells[$row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue) - $ws.Cells[$row, $ColumnIndex].Style.Font.UnderLine = $true - } - else { - $number = $null - if ( $numberRegex.IsMatch($v) -and # if it contains digit(s) - this syntax is quicker than -match for many items and cuts out slow checks for non numbers - $NoNumberConversion -ne '*' -and # and NoNumberConversion isn't specified - $NoNumberConversion -notcontains $Name -and - [Double]::TryParse($v, [System.Globalization.NumberStyles]::Any, [System.Globalization.NumberFormatInfo]::CurrentInfo, [Ref]$number) - ) { - $ws.Cells[$row, $ColumnIndex].Value = $number - if ($setNumformat) {$ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = $Numberformat } + elseif ($v -is [TimeSpan]) { + $ws.Cells[$row, $ColumnIndex].Value = $v + $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = '[h]:mm:ss' + } + elseif ($v -is [System.ValueType]) { + $ws.Cells[$row, $ColumnIndex].Value = $v + if ($setNumformat) { $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = $Numberformat } + } + elseif ($v -is [uri] ) { + $ws.Cells[$row, $ColumnIndex].HyperLink = $v + $ws.Cells[$row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue) + $ws.Cells[$row, $ColumnIndex].Style.Font.UnderLine = $true + } + elseif ($v -isnot [String] ) { + #Other objects or null. + if ($null -ne $v) { $ws.Cells[$row, $ColumnIndex].Value = $v.toString() } + } + elseif ($v[0] -eq '=') { + $ws.Cells[$row, $ColumnIndex].Formula = ($v -replace '^=', '') + if ($setNumformat) { $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = $Numberformat } + } + elseif ( [System.Uri]::IsWellFormedUriString($v , [System.UriKind]::Absolute) ) { + if ($v -match "^xl://internal/") { + $referenceAddress = $v -replace "^xl://internal/" , "" + $display = $referenceAddress -replace "!A1$" , "" + $h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display + $ws.Cells[$row, $ColumnIndex].HyperLink = $h + } + else { $ws.Cells[$row, $ColumnIndex].HyperLink = $v } #$ws.Cells[$row, $ColumnIndex].Value = $v.AbsoluteUri + $ws.Cells[$row, $ColumnIndex].Style.Font.Color.SetColor([System.Drawing.Color]::Blue) + $ws.Cells[$row, $ColumnIndex].Style.Font.UnderLine = $true } else { - $ws.Cells[$row, $ColumnIndex].Value = $v + $number = $null + if ( $numberRegex.IsMatch($v) -and # if it contains digit(s) - this syntax is quicker than -match for many items and cuts out slow checks for non numbers + $NoNumberConversion -ne '*' -and # and NoNumberConversion isn't specified + $NoNumberConversion -notcontains $Name -and + [Double]::TryParse($v, [System.Globalization.NumberStyles]::Any, [System.Globalization.NumberFormatInfo]::CurrentInfo, [Ref]$number) + ) { + $ws.Cells[$row, $ColumnIndex].Value = $number + if ($setNumformat) { $ws.Cells[$row, $ColumnIndex].Style.Numberformat.Format = $Numberformat } + } + else { + $ws.Cells[$row, $ColumnIndex].Value = $v + } } } + catch { Write-Warning -Message "Could not insert the '$Name' property at Row $row, Column $ColumnIndex" } + $ColumnIndex += 1 } - catch {Write-Warning -Message "Could not insert the '$Name' property at Row $row, Column $ColumnIndex"} - $ColumnIndex += 1 + $ColumnIndex -= 1 # column index will be the last column whether isDataTypeValueType was true or false + #endregion } - $ColumnIndex -= 1 # column index will be the last column whether isDataTypeValueType was true or false - #endregion } + catch { throw "Failed exporting data to worksheet '$WorksheetName' to '$Path': $_" } } - catch {throw "Failed exporting data to worksheet '$WorksheetName' to '$Path': $_" } - }} + } end { if ($firstTimeThru -and $ws.Dimension) { - $LastRow = $ws.Dimension.End.Row - $LastCol = $ws.Dimension.End.Column - $endAddress = $ws.Dimension.End.Address + $LastRow = $ws.Dimension.End.Row + $LastCol = $ws.Dimension.End.Column + $endAddress = $ws.Dimension.End.Address } else { - $LastRow = $row - $LastCol = $ColumnIndex - $endAddress = [OfficeOpenXml.ExcelAddress]::GetAddress($LastRow , $LastCol) + $LastRow = $row + $LastCol = $ColumnIndex + $endAddress = [OfficeOpenXml.ExcelAddress]::GetAddress($LastRow , $LastCol) } - $startAddress = [OfficeOpenXml.ExcelAddress]::GetAddress($StartRow, $StartColumn) - $dataRange = "{0}:{1}" -f $startAddress, $endAddress + $startAddress = [OfficeOpenXml.ExcelAddress]::GetAddress($StartRow, $StartColumn) + $dataRange = "{0}:{1}" -f $startAddress, $endAddress Write-Debug "Data Range '$dataRange'" if ($AutoNameRange) { @@ -385,13 +388,14 @@ # if there aren't any headers, use the the first row of data to name the ranges: this is the last point that headers will be used. $headerRange = $ws.Dimension.Address -replace "\d+$", $StartRow #using a slightly odd syntax otherwise header ends up as a 2D array - $ws.Cells[$headerRange].Value | ForEach-Object -Begin {$Script:header = @()} -Process {$Script:header += $_ } - if ($PSBoundParameters.ContainsKey($TargetData)) { #if Export was called with data that writes no header start the range at $startRow ($startRow is data) - $targetRow = $StartRow + $ws.Cells[$headerRange].Value | ForEach-Object -Begin { $Script:header = @() } -Process { $Script:header += $_ } + if ($PSBoundParameters.ContainsKey($TargetData)) { + #if Export was called with data that writes no header start the range at $startRow ($startRow is data) + $targetRow = $StartRow } else { $targetRow = $StartRow + 1 } #if Export was called without data to add names (assume $startRow is a header) or... } # ... called with data that writes a header, then start the range at $startRow + 1 - else { $targetRow = $StartRow + 1 } + else { $targetRow = $StartRow + 1 } #Dimension.start.row always seems to be one so we work out the target row #, but start.column is the first populated one and .Columns is the count of populated ones. @@ -400,7 +404,8 @@ foreach ($c in 0..($LastCol - $StartColumn)) { $targetRangeName = @($script:Header)[$c] #Let Add-ExcelName fix (and warn about) bad names Add-ExcelName -RangeName $targetRangeName -Range $ws.Cells[$targetRow, ($StartColumn + $c ), $LastRow, ($StartColumn + $c )] - try {#this test can throw with some names, surpress any error + try { + #this test can throw with some names, surpress any error if ([OfficeOpenXml.FormulaParsing.ExcelUtilities.ExcelAddressUtil]::IsValidAddress(($targetRangeName -replace '\W' , '_' ))) { Write-Warning -Message "AutoNameRange: Property name '$targetRangeName' is also a valid Excel address and may cause issues. Consider renaming the property." } @@ -410,13 +415,13 @@ } } } - catch {Write-Warning -Message "Failed adding named ranges to worksheet '$WorksheetName': $_" } + catch { Write-Warning -Message "Failed adding named ranges to worksheet '$WorksheetName': $_" } } #Empty string is not allowed as a name for ranges or tables. - if ($RangeName) { Add-ExcelName -Range $ws.Cells[$dataRange] -RangeName $RangeName} + if ($RangeName) { Add-ExcelName -Range $ws.Cells[$dataRange] -RangeName $RangeName } #Allow table to be inserted by specifying Name, or Style or both; only process autoFilter if there is no table (they clash). - if ($null -ne $TableName -or $PSBoundParameters.ContainsKey('TableStyle')) { + if ($null -ne $TableName -or $PSBoundParameters.ContainsKey('TableStyle')) { #Already inserted Excel table if input was a DataTable if ($InputObject -isnot [System.Data.DataTable]) { Add-ExcelTable -Range $ws.Cells[$dataRange] -TableName $TableName -TableStyle $TableStyle @@ -427,19 +432,19 @@ $ws.Cells[$dataRange].AutoFilter = $true Write-Verbose -Message "Enabled autofilter. " } - catch {Write-Warning -Message "Failed adding autofilter to worksheet '$WorksheetName': $_"} + catch { Write-Warning -Message "Failed adding autofilter to worksheet '$WorksheetName': $_" } } if ($PivotTableDefinition) { foreach ($item in $PivotTableDefinition.GetEnumerator()) { $params = $item.value - if ($Activate) {$params.Activate = $true } + if ($Activate) { $params.Activate = $true } if ($params.keys -notcontains 'SourceRange' -and - ($params.Keys -notcontains 'SourceWorksheet' -or $params.SourceWorksheet -eq $WorksheetName)) {$params.SourceRange = $dataRange} - if ($params.Keys -notcontains 'SourceWorksheet') {$params.SourceWorksheet = $ws } - if ($params.Keys -notcontains 'NoTotalsInPivot' -and $NoTotalsInPivot ) {$params.PivotTotals = 'None'} - if ($params.Keys -notcontains 'PivotTotals' -and $PivotTotals ) {$params.PivotTotals = $PivotTotals} - if ($params.Keys -notcontains 'PivotDataToColumn' -and $PivotDataToColumn) {$params.PivotDataToColumn = $true} + ($params.Keys -notcontains 'SourceWorksheet' -or $params.SourceWorksheet -eq $WorksheetName)) { $params.SourceRange = $dataRange } + if ($params.Keys -notcontains 'SourceWorksheet') { $params.SourceWorksheet = $ws } + if ($params.Keys -notcontains 'NoTotalsInPivot' -and $NoTotalsInPivot ) { $params.PivotTotals = 'None' } + if ($params.Keys -notcontains 'PivotTotals' -and $PivotTotals ) { $params.PivotTotals = $PivotTotals } + if ($params.Keys -notcontains 'PivotDataToColumn' -and $PivotDataToColumn) { $params.PivotDataToColumn = $true } Add-PivotTable -ExcelPackage $pkg -PivotTableName $item.key @Params } @@ -453,23 +458,23 @@ $PivotTableName += 'Pivot' } - if ($PivotTableName) {$params.PivotTableName = $PivotTableName} - else {$params.PivotTableName = $WorksheetName + 'PivotTable'} - if ($Activate) {$params.Activate = $true } - if ($PivotFilter) {$params.PivotFilter = $PivotFilter} - if ($PivotRows) {$params.PivotRows = $PivotRows} - if ($PivotColumns) {$Params.PivotColumns = $PivotColumns} - if ($PivotData) {$Params.PivotData = $PivotData} - if ($NoTotalsInPivot) {$params.PivotTotals = "None" } - Elseif ($PivotTotals) {$params.PivotTotals = $PivotTotals} - if ($PivotDataToColumn) {$params.PivotDataToColumn = $true} + if ($PivotTableName) { $params.PivotTableName = $PivotTableName } + else { $params.PivotTableName = $WorksheetName + 'PivotTable' } + if ($Activate) { $params.Activate = $true } + if ($PivotFilter) { $params.PivotFilter = $PivotFilter } + if ($PivotRows) { $params.PivotRows = $PivotRows } + if ($PivotColumns) { $Params.PivotColumns = $PivotColumns } + if ($PivotData) { $Params.PivotData = $PivotData } + if ($NoTotalsInPivot) { $params.PivotTotals = "None" } + Elseif ($PivotTotals) { $params.PivotTotals = $PivotTotals } + if ($PivotDataToColumn) { $params.PivotDataToColumn = $true } if ($IncludePivotChart -or $PSBoundParameters.ContainsKey('PivotChartType')) { - $params.IncludePivotChart = $true - $Params.ChartType = $PivotChartType - if ($ShowCategory) {$params.ShowCategory = $true} - if ($ShowPercent) {$params.ShowPercent = $true} - if ($NoLegend) {$params.NoLegend = $true} + $params.IncludePivotChart = $true + $Params.ChartType = $PivotChartType + if ($ShowCategory) { $params.ShowCategory = $true } + if ($ShowPercent) { $params.ShowPercent = $true } + if ($NoLegend) { $params.NoLegend = $true } } Add-PivotTable -ExcelPackage $pkg -SourceWorksheet $ws @params } @@ -513,9 +518,10 @@ } } } - catch {Write-Warning -Message "Failed adding Freezing the panes in worksheet '$WorksheetName': $_"} + catch { Write-Warning -Message "Failed adding Freezing the panes in worksheet '$WorksheetName': $_" } - if ($PSBoundParameters.ContainsKey("BoldTopRow")) { #it sets bold as far as there are populated cells: for whole row could do $ws.row($x).style.font.bold = $true + if ($PSBoundParameters.ContainsKey("BoldTopRow")) { + #it sets bold as far as there are populated cells: for whole row could do $ws.row($x).style.font.bold = $true try { if ($Title) { $range = $ws.Dimension.Address -replace '\d+', ($StartRow + 1) @@ -526,41 +532,41 @@ $ws.Cells[$range].Style.Font.Bold = [boolean]$BoldTopRow Write-Verbose -Message "Set $range font style to bold." } - catch {Write-Warning -Message "Failed setting the top row to bold in worksheet '$WorksheetName': $_"} + catch { Write-Warning -Message "Failed setting the top row to bold in worksheet '$WorksheetName': $_" } } if ($AutoSize -and -not $env:NoAutoSize) { try { #Don't fit the all the columns in the sheet; if we are adding cells beside things with hidden columns, that unhides them if ($MaxAutoSizeRows -and $MaxAutoSizeRows -lt $LastRow ) { - $AutosizeRange = [OfficeOpenXml.ExcelAddress]::GetAddress($startRow,$StartColumn, $MaxAutoSizeRows , $LastCol) + $AutosizeRange = [OfficeOpenXml.ExcelAddress]::GetAddress($startRow, $StartColumn, $MaxAutoSizeRows , $LastCol) $ws.Cells[$AutosizeRange].AutoFitColumns() } - else {$ws.Cells[$dataRange].AutoFitColumns() } + else { $ws.Cells[$dataRange].AutoFitColumns() } Write-Verbose -Message "Auto-sized columns" } - catch { Write-Warning -Message "Failed autosizing columns of worksheet '$WorksheetName': $_"} + catch { Write-Warning -Message "Failed autosizing columns of worksheet '$WorksheetName': $_" } } - elseif ($AutoSize) {Write-Warning -Message "Auto-fitting columns is not available with this OS configuration." } + elseif ($AutoSize) { Write-Warning -Message "Auto-fitting columns is not available with this OS configuration." } foreach ($Sheet in $HideSheet) { try { - $pkg.Workbook.Worksheets.Where({$_.Name -like $sheet}) | ForEach-Object { + $pkg.Workbook.Worksheets.Where({ $_.Name -like $sheet }) | ForEach-Object { $_.Hidden = 'Hidden' Write-verbose -Message "Sheet '$($_.Name)' Hidden." } } - catch {Write-Warning -Message "Failed hiding worksheet '$sheet': $_"} + catch { Write-Warning -Message "Failed hiding worksheet '$sheet': $_" } } foreach ($Sheet in $UnHideSheet) { try { - $pkg.Workbook.Worksheets.Where({$_.Name -like $sheet}) | ForEach-Object { + $pkg.Workbook.Worksheets.Where({ $_.Name -like $sheet }) | ForEach-Object { $_.Hidden = 'Visible' Write-verbose -Message "Sheet '$($_.Name)' shown" } } - catch {Write-Warning -Message "Failed showing worksheet '$sheet': $_"} + catch { Write-Warning -Message "Failed showing worksheet '$sheet': $_" } } - if (-not $pkg.Workbook.Worksheets.Where({$_.Hidden -eq 'visible'})) { + if (-not $pkg.Workbook.Worksheets.Where({ $_.Hidden -eq 'visible' })) { Write-Verbose -Message "No Sheets were left visible, making $WorksheetName visible" $ws.Hidden = 'Visible' } @@ -568,46 +574,46 @@ foreach ($chartDef in $ExcelChartDefinition) { if ($chartDef -is [System.Management.Automation.PSCustomObject]) { $params = @{} - $chartDef.PSObject.Properties | ForEach-Object {if ( $null -ne $_.value) {$params[$_.name] = $_.value}} + $chartDef.PSObject.Properties | ForEach-Object { if ( $null -ne $_.value) { $params[$_.name] = $_.value } } Add-ExcelChart -Worksheet $ws @params } - elseif ($chartDef -is [hashtable] -or $chartDef -is[System.Collections.Specialized.OrderedDictionary]) { + elseif ($chartDef -is [hashtable] -or $chartDef -is [System.Collections.Specialized.OrderedDictionary]) { Add-ExcelChart -Worksheet $ws @chartDef } } if ($Calculate) { - try { [OfficeOpenXml.CalculationExtension]::Calculate($ws) } - catch { Write-Warning "One or more errors occured while calculating, save will continue, but there may be errors in the workbook. $_"} + try { [OfficeOpenXml.CalculationExtension]::Calculate($ws) } + catch { Write-Warning "One or more errors occured while calculating, save will continue, but there may be errors in the workbook. $_" } } if ($Barchart -or $PieChart -or $LineChart -or $ColumnChart) { - if ($NoHeader) {$FirstDataRow = $startRow} - else {$FirstDataRow = $startRow + 1 } + if ($NoHeader) { $FirstDataRow = $startRow } + else { $FirstDataRow = $startRow + 1 } $range = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $startColumn, $FirstDataRow, $lastCol ) - $xCol = $ws.cells[$range] | Where-Object {$_.value -is [string] } | ForEach-Object {$_.start.column} | Sort-Object | Select-Object -first 1 + $xCol = $ws.cells[$range] | Where-Object { $_.value -is [string] } | ForEach-Object { $_.start.column } | Sort-Object | Select-Object -first 1 if (-not $xcol) { - $xcol = $StartColumn - $range = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, ($startColumn +1), $FirstDataRow, $lastCol ) + $xcol = $StartColumn + $range = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, ($startColumn + 1), $FirstDataRow, $lastCol ) } - $yCol = $ws.cells[$range] | Where-Object {$_.value -is [valueType] -or $_.Formula } | ForEach-Object {$_.start.column} | Sort-Object | Select-Object -first 1 - if (-not ($xCol -and $ycol)) { Write-Warning -Message "Can't identify a string column and a number column to use as chart labels and data. "} + $yCol = $ws.cells[$range] | Where-Object { $_.value -is [valueType] -or $_.Formula } | ForEach-Object { $_.start.column } | Sort-Object | Select-Object -first 1 + if (-not ($xCol -and $ycol)) { Write-Warning -Message "Can't identify a string column and a number column to use as chart labels and data. " } else { $params = @{ - XRange = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $xcol , $lastrow, $xcol) - YRange = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $ycol , $lastrow, $ycol) - Title = '' - Column = ($lastCol +1) - Width = 800 + XRange = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $xcol , $lastrow, $xcol) + YRange = [OfficeOpenXml.ExcelAddress]::GetAddress($FirstDataRow, $ycol , $lastrow, $ycol) + Title = '' + Column = ($lastCol + 1) + Width = 800 } - if ($ShowPercent) {$params["ShowPercent"] = $true} - if ($ShowCategory) {$params["ShowCategory"] = $true} - if ($NoLegend) {$params["NoLegend"] = $true} - if (-not $NoHeader) {$params["SeriesHeader"] = $ws.Cells[$startRow, $YCol].Value} - if ($ColumnChart) {$Params["chartType"] = "ColumnStacked" } - elseif ($Barchart) {$Params["chartType"] = "BarStacked" } - elseif ($PieChart) {$Params["chartType"] = "PieExploded3D" } - elseif ($LineChart) {$Params["chartType"] = "Line" } + if ($ShowPercent) { $params["ShowPercent"] = $true } + if ($ShowCategory) { $params["ShowCategory"] = $true } + if ($NoLegend) { $params["NoLegend"] = $true } + if (-not $NoHeader) { $params["SeriesHeader"] = $ws.Cells[$startRow, $YCol].Value } + if ($ColumnChart) { $Params["chartType"] = "ColumnStacked" } + elseif ($Barchart) { $Params["chartType"] = "BarStacked" } + elseif ($PieChart) { $Params["chartType"] = "PieExploded3D" } + elseif ($LineChart) { $Params["chartType"] = "Line" } Add-ExcelChart -Worksheet $ws @params } @@ -615,35 +621,36 @@ # It now doesn't matter if the conditional formating rules are passed in $conditionalText or $conditional format. # Just one with an alias for compatiblity it will break things for people who are using both at once - foreach ($c in (@() + $ConditionalText + $ConditionalFormat) ) { + foreach ($c in (@() + $ConditionalText + $ConditionalFormat) ) { try { #we can take an object with a .ConditionalType property made by New-ConditionalText or with a .Formatter Property made by New-ConditionalFormattingIconSet or a hash table if ($c.ConditionalType) { - $cfParams = @{RuleType = $c.ConditionalType; ConditionValue = $c.Text ; - BackgroundColor = $c.BackgroundColor; BackgroundPattern = $c.PatternType ; - ForeGroundColor = $c.ConditionalTextColor} - if ($c.Range) {$cfParams.Range = $c.Range} - else {$cfParams.Range = $ws.Dimension.Address } + $cfParams = @{RuleType = $c.ConditionalType; ConditionValue = $c.Text ; + BackgroundColor = $c.BackgroundColor; BackgroundPattern = $c.PatternType ; + ForeGroundColor = $c.ConditionalTextColor + } + if ($c.Range) { $cfParams.Range = $c.Range } + else { $cfParams.Range = $ws.Dimension.Address } Add-ConditionalFormatting -Worksheet $ws @cfParams Write-Verbose -Message "Added conditional formatting to range $($c.range)" } - elseif ($c.formatter) { + elseif ($c.formatter) { switch ($c.formatter) { - "ThreeIconSet" {Add-ConditionalFormatting -Worksheet $ws -ThreeIconsSet $c.IconType -range $c.range -reverse:$c.reverse } - "FourIconSet" {Add-ConditionalFormatting -Worksheet $ws -FourIconsSet $c.IconType -range $c.range -reverse:$c.reverse } - "FiveIconSet" {Add-ConditionalFormatting -Worksheet $ws -FiveIconsSet $c.IconType -range $c.range -reverse:$c.reverse } + "ThreeIconSet" { Add-ConditionalFormatting -Worksheet $ws -ThreeIconsSet $c.IconType -range $c.range -reverse:$c.reverse } + "FourIconSet" { Add-ConditionalFormatting -Worksheet $ws -FourIconsSet $c.IconType -range $c.range -reverse:$c.reverse } + "FiveIconSet" { Add-ConditionalFormatting -Worksheet $ws -FiveIconsSet $c.IconType -range $c.range -reverse:$c.reverse } } Write-Verbose -Message "Added conditional formatting to range $($c.range)" } - elseif ($c -is [hashtable] -or $c -is[System.Collections.Specialized.OrderedDictionary]) { - if (-not $c.Range -or $c.Address) {$c.Address = $ws.Dimension.Address } + elseif ($c -is [hashtable] -or $c -is [System.Collections.Specialized.OrderedDictionary]) { + if (-not $c.Range -or $c.Address) { $c.Address = $ws.Dimension.Address } Add-ConditionalFormatting -Worksheet $ws @c } } - catch {throw "Error applying conditional formatting to worksheet $_"} + catch { throw "Error applying conditional formatting to worksheet $_" } } foreach ($s in $Style) { - if (-not $s.Range) {$s["Range"] = $ws.Dimension.Address } + if (-not $s.Range) { $s["Range"] = $ws.Dimension.Address } Set-ExcelRange -Worksheet $ws @s } if ($CellStyleSB) { @@ -652,7 +659,7 @@ $LastColumn = $ws.Dimension.Address -replace "^.*:(\w*)\d+$" , '$1' & $CellStyleSB $ws $TotalRows $LastColumn } - catch {Write-Warning -Message "Failed processing CellStyleSB in worksheet '$WorksheetName': $_"} + catch { Write-Warning -Message "Failed processing CellStyleSB in worksheet '$WorksheetName': $_" } } #Can only add password, may want to support -password $Null removing password. @@ -661,32 +668,18 @@ $ws.Protection.SetPassword($Password) Write-Verbose -Message 'Set password on workbook' } - catch {throw "Failed setting password for worksheet '$WorksheetName': $_"} + catch { throw "Failed setting password for worksheet '$WorksheetName': $_" } } - if ($PassThru) { $pkg } + if ($PassThru) { $pkg } else { - if ($ReturnRange) {$dataRange } + if ($ReturnRange) { $dataRange } - if ($Password) { $pkg.Save($Password) } - else { $pkg.Save() } + if ($Password) { $pkg.Save($Password) } + else { $pkg.Save() } Write-Verbose -Message "Saved workbook $($pkg.File)" if ($ReZip) { - Write-Verbose -Message "Re-Zipping $($pkg.file) using .NET ZIP library" - try { - Add-Type -AssemblyName 'System.IO.Compression.Filesystem' -ErrorAction stop - } - catch { - Write-Error "The -ReZip parameter requires .NET Framework 4.5 or later to be installed. Recommend to install Powershell v4+" - continue - } - try { - $TempZipPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName()) - $null = [io.compression.zipfile]::ExtractToDirectory($pkg.File, $TempZipPath) - Remove-Item $pkg.File -Force - $null = [io.compression.zipfile]::CreateFromDirectory($TempZipPath, $pkg.File) - } - catch {throw "Error resizipping $path : $_"} + Invoke-ExcelReZipFile -ExcelPackage $pkg } $pkg.Dispose() From d69b640edc933f39288cb5306b565fa9a2fdb017 Mon Sep 17 00:00:00 2001 From: dfinke Date: Thu, 30 Dec 2021 14:39:33 -0500 Subject: [PATCH 080/140] Add FreezePane Example --- Examples/Freeze/FreezePane.ps1 | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Examples/Freeze/FreezePane.ps1 diff --git a/Examples/Freeze/FreezePane.ps1 b/Examples/Freeze/FreezePane.ps1 new file mode 100644 index 0000000..6c15f96 --- /dev/null +++ b/Examples/Freeze/FreezePane.ps1 @@ -0,0 +1,54 @@ +# Freeze the columns/rows to left and above the cell + +$data = ConvertFrom-Csv @" +Region,State,Units,Price,Name,NA,EU,JP,Other +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +West,Texas,927,923.71,Wii Sports,41.49,29.02,3.77,8.46 +"@ + +$xlfilename = "test.xlsx" +Remove-Item $xlfilename -ErrorAction SilentlyContinue + +<# + Freezes the top two rows and the two leftmost column +#> + +$data | Export-Excel $xlfilename -Show -Title 'Sales Data' -FreezePane 3, 3 \ No newline at end of file From 91da711635e1c498b02228b2b0bf6e4ca6a9e683 Mon Sep 17 00:00:00 2001 From: Josh Hendricks Date: Tue, 1 Feb 2022 21:37:55 -0800 Subject: [PATCH 081/140] docs: add Add-ExcelImage example --- Examples/AddPicture/Add-ExcelImage.ps1 | 115 +++++++++++++++++++++++++ Examples/AddPicture/AddPicture.ps1 | 34 ++++++++ Examples/AddPicture/Octocat.jpg | Bin 0 -> 6272 bytes Examples/AddPicture/README.md | 19 ++++ 4 files changed, 168 insertions(+) create mode 100644 Examples/AddPicture/Add-ExcelImage.ps1 create mode 100644 Examples/AddPicture/AddPicture.ps1 create mode 100644 Examples/AddPicture/Octocat.jpg create mode 100644 Examples/AddPicture/README.md diff --git a/Examples/AddPicture/Add-ExcelImage.ps1 b/Examples/AddPicture/Add-ExcelImage.ps1 new file mode 100644 index 0000000..c3e6d17 --- /dev/null +++ b/Examples/AddPicture/Add-ExcelImage.ps1 @@ -0,0 +1,115 @@ +function Add-ExcelImage { + <# + .SYNOPSIS + Adds an image to a worksheet in an Excel package. + .DESCRIPTION + Adds an image to a worksheet in an Excel package using the + `WorkSheet.Drawings.AddPicture(name, image)` method, and places the + image at the location specified by the Row and Column parameters. + + Additional position adjustment can be made by providing RowOffset and + ColumnOffset values in pixels. + .EXAMPLE + $image = [System.Drawing.Image]::FromFile($octocat) + $xlpkg = $data | Export-Excel -Path $path -PassThru + $xlpkg.Sheet1 | Add-ExcelImage -Image $image -Row 4 -Column 6 -ResizeCell + + Where $octocat is a path to an image file, and $data is a collection of + data to be exported, and $path is the output path for the Excel document, + Add-Excel places the image at row 4 and column 6, resizing the column + and row as needed to fit the image. + .INPUTS + [OfficeOpenXml.ExcelWorksheet] + .OUTPUTS + None + #> + [CmdletBinding()] + param( + # Specifies the worksheet to add the image to. + [Parameter(Mandatory, ValueFromPipeline)] + [OfficeOpenXml.ExcelWorksheet] + $WorkSheet, + + # Specifies the Image to be added to the worksheet. + [Parameter(Mandatory)] + [System.Drawing.Image] + $Image, + + # Specifies the row where the image will be placed. Rows are counted from 1. + [Parameter(Mandatory)] + [ValidateRange(1, [int]::MaxValue)] + [int] + $Row, + + # Specifies the column where the image will be placed. Columns are counted from 1. + [Parameter(Mandatory)] + [ValidateRange(1, [int]::MaxValue)] + [int] + $Column, + + # Specifies the name to associate with the image. Names must be unique per sheet. + # Omit the name and a GUID will be used instead. + [Parameter()] + [string] + $Name, + + # Specifies the number of pixels to offset the image on the Y-axis. A + # positive number moves the image down by the specified number of pixels + # from the top border of the cell. + [Parameter()] + [int] + $RowOffset = 1, + + # Specifies the number of pixels to offset the image on the X-axis. A + # positive number moves the image to the right by the specified number + # of pixels from the left border of the cell. + [Parameter()] + [int] + $ColumnOffset = 1, + + # Increase the column width and row height to fit the image if the current + # dimensions are smaller than the image provided. + [Parameter()] + [switch] + $ResizeCell + ) + + begin { + <# + These ratios work on my machine but it feels fragile. Need to better + understand how row and column sizing works in Excel and what the + width and height units represent. + #> + $widthFactor = 1 / 7 + $heightFactor = 3 / 4 + } + + process { + if ([string]::IsNullOrWhiteSpace($Name)) { + $Name = (New-Guid).ToString() + } + if ($null -ne $WorkSheet.Drawings[$Name]) { + Write-Error "A picture with the name `"$Name`" already exists in worksheet $($WorkSheet.Name)." + return + } + + <# + The row and column offsets of 1 ensures that the image lands just + inside the gray cell borders at the top left. + #> + $picture = $WorkSheet.Drawings.AddPicture($Name, $Image) + $picture.SetPosition($Row - 1, $RowOffset, $Column - 1, $ColumnOffset) + + if ($ResizeCell) { + <# + Adding 1 to the image height and width ensures that when the + row and column are resized, the bottom right of the image lands + just inside the gray cell borders at the bottom right. + #> + $width = $widthFactor * ($Image.Width + 1) + $height = $heightFactor * ($Image.Height + 1) + $WorkSheet.Column($Column).Width = [Math]::Max($width, $WorkSheet.Column($Column).Width) + $WorkSheet.Row($Row).Height = [Math]::Max($height, $WorkSheet.Row($Row).Height) + } + } +} \ No newline at end of file diff --git a/Examples/AddPicture/AddPicture.ps1 b/Examples/AddPicture/AddPicture.ps1 new file mode 100644 index 0000000..5230641 --- /dev/null +++ b/Examples/AddPicture/AddPicture.ps1 @@ -0,0 +1,34 @@ +Add-Type -AssemblyName System.Drawing + +. $PSScriptRoot\Add-ExcelImage.ps1 + +$data = ConvertFrom-Csv @" +Region,State,Units,Price +West,Texas,927,923.71 +North,Tennessee,466,770.67 +East,Florida,520,458.68 +East,Maine,828,661.24 +West,Virginia,465,053.58 +North,Missouri,436,235.67 +South,Kansas,214,992.47 +North,North Dakota,789,640.72 +South,Delaware,712,508.55 +"@ + +$path = "$PSScriptRoot/Add-Picture-test.xlsx" +Remove-Item $path -ErrorAction SilentlyContinue + + +try { + $octocat = "$PSScriptRoot/Octocat.jpg" + $image = [System.Drawing.Image]::FromFile($octocat) + $xlpkg = $data | Export-Excel -Path $path -PassThru + $xlpkg.Sheet1 | Add-ExcelImage -Image $image -Row 4 -Column 6 -ResizeCell +} finally { + $image.Dispose() + if ($xlpkg) { + Close-ExcelPackage -ExcelPackage $xlpkg -Show + } +} + + diff --git a/Examples/AddPicture/Octocat.jpg b/Examples/AddPicture/Octocat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a48c3499c8f316eae14f1722c2fa2004d06e8b69 GIT binary patch literal 6272 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 ix?hH#H(+CXxz*IWU;X2Ky8Eo literal 0 HcmV?d00001 diff --git a/Examples/AddPicture/README.md b/Examples/AddPicture/README.md new file mode 100644 index 0000000..ff36c37 --- /dev/null +++ b/Examples/AddPicture/README.md @@ -0,0 +1,19 @@ +# Add-ExcelImage Example + +Adding pictures to an Excel worksheet is possible by calling the `AddPicture(name, image)` +method on the `Drawings` property of an `ExcelWorksheet` object. + +The `Add-ExcelImage` example here demonstrates how to add a picture at a given +cell location, and optionally resize the row and column to fit the image. + +Care has been taken in this example to get the image placement to be just inside +the cell border, and if the `-ResizeCell` switch is present, the height and width +of the row and column will be increased, if needed, so that the bottom right of +the image also lands just inside the cell border. + +The Excel row and column sizes are measured in "point" units rather than pixels, +and at the moment a fixed multiplication factor is used to convert the size of +the image in pixels, to the corresponding height and width values in Excel. + +You may find that images with a different DPI, or different resolution, DPI, or +text scaling options result in imperfect row and column sizing. \ No newline at end of file From cf5d3f83d6bb13176fd57252373b2a47fddfaa66 Mon Sep 17 00:00:00 2001 From: Josh Hendricks Date: Wed, 2 Feb 2022 08:16:22 -0800 Subject: [PATCH 082/140] docs: Update readme --- Examples/AddPicture/AddPicture.ps1 | 6 +++--- Examples/AddPicture/README.md | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Examples/AddPicture/AddPicture.ps1 b/Examples/AddPicture/AddPicture.ps1 index 5230641..d5e04fe 100644 --- a/Examples/AddPicture/AddPicture.ps1 +++ b/Examples/AddPicture/AddPicture.ps1 @@ -25,10 +25,10 @@ try { $xlpkg = $data | Export-Excel -Path $path -PassThru $xlpkg.Sheet1 | Add-ExcelImage -Image $image -Row 4 -Column 6 -ResizeCell } finally { - $image.Dispose() + if ($image) { + $image.Dispose() + } if ($xlpkg) { Close-ExcelPackage -ExcelPackage $xlpkg -Show } } - - diff --git a/Examples/AddPicture/README.md b/Examples/AddPicture/README.md index ff36c37..8127209 100644 --- a/Examples/AddPicture/README.md +++ b/Examples/AddPicture/README.md @@ -6,14 +6,28 @@ method on the `Drawings` property of an `ExcelWorksheet` object. The `Add-ExcelImage` example here demonstrates how to add a picture at a given cell location, and optionally resize the row and column to fit the image. +## Running the example + +To try this example, run the script `AddPicture.ps1`. The `Add-ExcelImage` +function will be dot-sourced, and an Excel document will be created in the same +folder with a sample data set. The Octocat image will then be embedded into +Sheet1. + +The creation of the Excel document and the `System.Drawing.Image` object +representing Octocat are properly disposed within a `finally` block to ensure +that the resources are released, even if an error occurs in the `try` block. + +## Note about column and row sizing + Care has been taken in this example to get the image placement to be just inside the cell border, and if the `-ResizeCell` switch is present, the height and width of the row and column will be increased, if needed, so that the bottom right of the image also lands just inside the cell border. The Excel row and column sizes are measured in "point" units rather than pixels, -and at the moment a fixed multiplication factor is used to convert the size of -the image in pixels, to the corresponding height and width values in Excel. +and a fixed multiplication factor is used to convert the size of the image in +pixels, to the corresponding height and width values in Excel. -You may find that images with a different DPI, or different resolution, DPI, or -text scaling options result in imperfect row and column sizing. \ No newline at end of file +It's possible that different DPI or text scaling options could result in +imperfect column and row sizing and if a better strategy is found for converting +the image dimensions to column and row sizes, this example will be updated. From f33215382af9c0e68ce168dd245316c944911dce Mon Sep 17 00:00:00 2001 From: Josh Hendricks Date: Wed, 2 Feb 2022 08:31:35 -0800 Subject: [PATCH 083/140] docs: rename to AddImage for consistency --- .../{AddPicture => AddImage}/Add-ExcelImage.ps1 | 0 .../AddPicture.ps1 => AddImage/AddImage.ps1} | 0 Examples/{AddPicture => AddImage}/Octocat.jpg | Bin Examples/{AddPicture => AddImage}/README.md | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename Examples/{AddPicture => AddImage}/Add-ExcelImage.ps1 (100%) rename Examples/{AddPicture/AddPicture.ps1 => AddImage/AddImage.ps1} (100%) rename Examples/{AddPicture => AddImage}/Octocat.jpg (100%) rename Examples/{AddPicture => AddImage}/README.md (95%) diff --git a/Examples/AddPicture/Add-ExcelImage.ps1 b/Examples/AddImage/Add-ExcelImage.ps1 similarity index 100% rename from Examples/AddPicture/Add-ExcelImage.ps1 rename to Examples/AddImage/Add-ExcelImage.ps1 diff --git a/Examples/AddPicture/AddPicture.ps1 b/Examples/AddImage/AddImage.ps1 similarity index 100% rename from Examples/AddPicture/AddPicture.ps1 rename to Examples/AddImage/AddImage.ps1 diff --git a/Examples/AddPicture/Octocat.jpg b/Examples/AddImage/Octocat.jpg similarity index 100% rename from Examples/AddPicture/Octocat.jpg rename to Examples/AddImage/Octocat.jpg diff --git a/Examples/AddPicture/README.md b/Examples/AddImage/README.md similarity index 95% rename from Examples/AddPicture/README.md rename to Examples/AddImage/README.md index 8127209..4d71141 100644 --- a/Examples/AddPicture/README.md +++ b/Examples/AddImage/README.md @@ -8,7 +8,7 @@ cell location, and optionally resize the row and column to fit the image. ## Running the example -To try this example, run the script `AddPicture.ps1`. The `Add-ExcelImage` +To try this example, run the script `AddImage.ps1`. The `Add-ExcelImage` function will be dot-sourced, and an Excel document will be created in the same folder with a sample data set. The Octocat image will then be embedded into Sheet1. From 5ab6a9116d03d86269de4945cadd92bb9492032c Mon Sep 17 00:00:00 2001 From: dfinke Date: Thu, 3 Feb 2022 18:43:15 -0500 Subject: [PATCH 084/140] @joshooaj added throw if not on Windows, pls review --- Examples/AddImage/Add-ExcelImage.ps1 | 4 ++++ Examples/AddImage/AddImage.ps1 | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Examples/AddImage/Add-ExcelImage.ps1 b/Examples/AddImage/Add-ExcelImage.ps1 index c3e6d17..38ce80e 100644 --- a/Examples/AddImage/Add-ExcelImage.ps1 +++ b/Examples/AddImage/Add-ExcelImage.ps1 @@ -75,6 +75,10 @@ function Add-ExcelImage { ) begin { + if ($IsWindows -eq $false) { + throw "This only works on Windows and won't run on $([environment]::OSVersion)" + } + <# These ratios work on my machine but it feels fragile. Need to better understand how row and column sizing works in Excel and what the diff --git a/Examples/AddImage/AddImage.ps1 b/Examples/AddImage/AddImage.ps1 index d5e04fe..4d38e09 100644 --- a/Examples/AddImage/AddImage.ps1 +++ b/Examples/AddImage/AddImage.ps1 @@ -1,3 +1,7 @@ +if ($IsWindows -eq $false) { + throw "This only works on Windows and won't run on $([environment]::OSVersion)" +} + Add-Type -AssemblyName System.Drawing . $PSScriptRoot\Add-ExcelImage.ps1 @@ -24,7 +28,8 @@ try { $image = [System.Drawing.Image]::FromFile($octocat) $xlpkg = $data | Export-Excel -Path $path -PassThru $xlpkg.Sheet1 | Add-ExcelImage -Image $image -Row 4 -Column 6 -ResizeCell -} finally { +} +finally { if ($image) { $image.Dispose() } From 556f0ac51ecdd43f9b1f4a7999488d0a431363ef Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 4 Feb 2022 17:28:30 -0500 Subject: [PATCH 085/140] Updated changelog --- changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.md b/changelog.md index 06b93ae..13d57c8 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,6 @@ +- Add images to spreadsheets. [Check it out](.\Examples\AddImage) + - Thank you to Josh Hendricks [GitHub](https://github.com/joshooaj) [Twitter](https://twitter.com/joshooaj) for the idea + # v7.4.1 - Implements: https://github.com/dfinke/ImportExcel/issues/1111 From c09083d350d076f898dc6d840d41511dd495a72d Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 4 Feb 2022 17:30:40 -0500 Subject: [PATCH 086/140] updated --- changelog.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 13d57c8..8638ba2 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,6 @@ -- Add images to spreadsheets. [Check it out](.\Examples\AddImage) - - Thank you to Josh Hendricks [GitHub](https://github.com/joshooaj) [Twitter](https://twitter.com/joshooaj) for the idea +- Thank you to Josh Hendricks + - Add images to spreadsheets. [Check it out](.\Examples\AddImage) + - Catch up with him on [GitHub](https://github.com/joshooaj) and [Twitter](https://twitter.com/joshooaj) for the idea # v7.4.1 From 0c8bb2300aed581bf507aa102a1f33cf79d858a5 Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 4 Feb 2022 17:31:39 -0500 Subject: [PATCH 087/140] update links --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 8638ba2..5f26638 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,5 @@ - Thank you to Josh Hendricks - - Add images to spreadsheets. [Check it out](.\Examples\AddImage) + - Add images to spreadsheets. [Check it out](https://github.com/dfinke/ImportExcel/tree/master/Examples/AddImage) - Catch up with him on [GitHub](https://github.com/joshooaj) and [Twitter](https://twitter.com/joshooaj) for the idea # v7.4.1 From 99beda7a107cb237f6b5103ca3c34f85db32358e Mon Sep 17 00:00:00 2001 From: Doug Finke Date: Sun, 6 Mar 2022 14:51:30 -0500 Subject: [PATCH 088/140] Move to mixed case folders --- {pivot => Pivot}/README.md | 0 {pivot => Pivot}/pivot.md | 0 examples/README.md | 2 -- examples/charts/README.md | 2 -- examples/charts/multiplecharts.md | 28 ------------------- examples/untitled.md | 2 -- {mdhelp => mdHelp}/README.md | 0 {mdhelp => mdHelp}/en/README.md | 0 .../en/add-conditionalformatting.md | 0 {mdhelp => mdHelp}/en/add-excelchart.md | 0 .../en/add-exceldatavalidationrule.md | 0 {mdhelp => mdHelp}/en/add-excelname.md | 0 {mdhelp => mdHelp}/en/add-exceltable.md | 0 {mdhelp => mdHelp}/en/add-pivottable.md | 0 {mdhelp => mdHelp}/en/add-worksheet.md | 0 {mdhelp => mdHelp}/en/close-excelpackage.md | 0 {mdhelp => mdHelp}/en/compare-worksheet.md | 0 .../en/convert-excelrangetoimage.md | 0 .../en/convertfrom-excelsheet.md | 0 .../en/convertfrom-exceltosqlinsert.md | 0 {mdhelp => mdHelp}/en/copy-excelworksheet.md | 0 {mdhelp => mdHelp}/en/expand-numberformat.md | 0 {mdhelp => mdHelp}/en/export-excel.md | 0 {mdhelp => mdHelp}/en/get-excelsheetinfo.md | 0 .../en/get-excelworkbookinfo.md | 0 {mdhelp => mdHelp}/en/import-excel.md | 0 {mdhelp => mdHelp}/en/join-worksheet.md | 0 {mdhelp => mdHelp}/en/merge-multiplesheets.md | 0 {mdhelp => mdHelp}/en/merge-worksheet.md | 0 .../en/new-conditionalformattingiconset.md | 0 {mdhelp => mdHelp}/en/new-conditionaltext.md | 0 .../en/new-excelchartdefinition.md | 0 .../en/new-pivottabledefinition.md | 0 {mdhelp => mdHelp}/en/open-excelpackage.md | 0 {mdhelp => mdHelp}/en/remove-worksheet.md | 0 {mdhelp => mdHelp}/en/select-worksheet.md | 0 {mdhelp => mdHelp}/en/send-sqldatatoexcel.md | 0 {mdhelp => mdHelp}/en/set-excelcolumn.md | 0 {mdhelp => mdHelp}/en/set-excelrange.md | 0 {mdhelp => mdHelp}/en/set-excelrow.md | 0 .../en/update-firstobjectproperties.md | 0 41 files changed, 34 deletions(-) rename {pivot => Pivot}/README.md (100%) rename {pivot => Pivot}/pivot.md (100%) delete mode 100644 examples/README.md delete mode 100644 examples/charts/README.md delete mode 100644 examples/charts/multiplecharts.md delete mode 100644 examples/untitled.md rename {mdhelp => mdHelp}/README.md (100%) rename {mdhelp => mdHelp}/en/README.md (100%) rename {mdhelp => mdHelp}/en/add-conditionalformatting.md (100%) rename {mdhelp => mdHelp}/en/add-excelchart.md (100%) rename {mdhelp => mdHelp}/en/add-exceldatavalidationrule.md (100%) rename {mdhelp => mdHelp}/en/add-excelname.md (100%) rename {mdhelp => mdHelp}/en/add-exceltable.md (100%) rename {mdhelp => mdHelp}/en/add-pivottable.md (100%) rename {mdhelp => mdHelp}/en/add-worksheet.md (100%) rename {mdhelp => mdHelp}/en/close-excelpackage.md (100%) rename {mdhelp => mdHelp}/en/compare-worksheet.md (100%) rename {mdhelp => mdHelp}/en/convert-excelrangetoimage.md (100%) rename {mdhelp => mdHelp}/en/convertfrom-excelsheet.md (100%) rename {mdhelp => mdHelp}/en/convertfrom-exceltosqlinsert.md (100%) rename {mdhelp => mdHelp}/en/copy-excelworksheet.md (100%) rename {mdhelp => mdHelp}/en/expand-numberformat.md (100%) rename {mdhelp => mdHelp}/en/export-excel.md (100%) rename {mdhelp => mdHelp}/en/get-excelsheetinfo.md (100%) rename {mdhelp => mdHelp}/en/get-excelworkbookinfo.md (100%) rename {mdhelp => mdHelp}/en/import-excel.md (100%) rename {mdhelp => mdHelp}/en/join-worksheet.md (100%) rename {mdhelp => mdHelp}/en/merge-multiplesheets.md (100%) rename {mdhelp => mdHelp}/en/merge-worksheet.md (100%) rename {mdhelp => mdHelp}/en/new-conditionalformattingiconset.md (100%) rename {mdhelp => mdHelp}/en/new-conditionaltext.md (100%) rename {mdhelp => mdHelp}/en/new-excelchartdefinition.md (100%) rename {mdhelp => mdHelp}/en/new-pivottabledefinition.md (100%) rename {mdhelp => mdHelp}/en/open-excelpackage.md (100%) rename {mdhelp => mdHelp}/en/remove-worksheet.md (100%) rename {mdhelp => mdHelp}/en/select-worksheet.md (100%) rename {mdhelp => mdHelp}/en/send-sqldatatoexcel.md (100%) rename {mdhelp => mdHelp}/en/set-excelcolumn.md (100%) rename {mdhelp => mdHelp}/en/set-excelrange.md (100%) rename {mdhelp => mdHelp}/en/set-excelrow.md (100%) rename {mdhelp => mdHelp}/en/update-firstobjectproperties.md (100%) diff --git a/pivot/README.md b/Pivot/README.md similarity index 100% rename from pivot/README.md rename to Pivot/README.md diff --git a/pivot/pivot.md b/Pivot/pivot.md similarity index 100% rename from pivot/pivot.md rename to Pivot/pivot.md diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 65afe60..0000000 --- a/examples/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Examples - diff --git a/examples/charts/README.md b/examples/charts/README.md deleted file mode 100644 index d7bba70..0000000 --- a/examples/charts/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Charts - diff --git a/examples/charts/multiplecharts.md b/examples/charts/multiplecharts.md deleted file mode 100644 index 56cbc30..0000000 --- a/examples/charts/multiplecharts.md +++ /dev/null @@ -1,28 +0,0 @@ -# Multiplecharts - -## PowerShell - -```text -$xlFile = "$env:TEMP\ImportExcelExample.xlsx" -Remove-Item $xlFile -ErrorAction Ignore - -$data = ConvertFrom-Csv @" -ID,Product,Quantity,Price,Total -12001,Nails,37,3.99,147.63 -12002,Hammer,5,12.10,60.5 -12003,Saw,12,15.37,184.44 -12010,Drill,20,8,160 -12011,Crowbar,7,23.48,164.36 -"@ - -$chart1 = New-ExcelChartDefinition -YRange "Price" -XRange "Product" -Title "Item price" -NoLegend -Height 225 -$chart2 = New-ExcelChartDefinition -YRange "Total "-XRange "Product" -Title "Total sales" -NoLegend -Height 225 -Row 9 -Column 15 -$chart3 = New-ExcelChartDefinition -YRange "Quantity"-XRange "Product" -Title "Sales volume" -NoLegend -Height 225 -Row 15 - -$data | Export-Excel -Path $xlFile -AutoFilter -AutoNameRange -AutoSize -Show -ExcelChartDefinition $chart1,$chart2,$chart3 -``` - -## Result - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/Examples/Charts/Multiplecharts.png) - diff --git a/examples/untitled.md b/examples/untitled.md deleted file mode 100644 index 5094080..0000000 --- a/examples/untitled.md +++ /dev/null @@ -1,2 +0,0 @@ -# Untitled - diff --git a/mdhelp/README.md b/mdHelp/README.md similarity index 100% rename from mdhelp/README.md rename to mdHelp/README.md diff --git a/mdhelp/en/README.md b/mdHelp/en/README.md similarity index 100% rename from mdhelp/en/README.md rename to mdHelp/en/README.md diff --git a/mdhelp/en/add-conditionalformatting.md b/mdHelp/en/add-conditionalformatting.md similarity index 100% rename from mdhelp/en/add-conditionalformatting.md rename to mdHelp/en/add-conditionalformatting.md diff --git a/mdhelp/en/add-excelchart.md b/mdHelp/en/add-excelchart.md similarity index 100% rename from mdhelp/en/add-excelchart.md rename to mdHelp/en/add-excelchart.md diff --git a/mdhelp/en/add-exceldatavalidationrule.md b/mdHelp/en/add-exceldatavalidationrule.md similarity index 100% rename from mdhelp/en/add-exceldatavalidationrule.md rename to mdHelp/en/add-exceldatavalidationrule.md diff --git a/mdhelp/en/add-excelname.md b/mdHelp/en/add-excelname.md similarity index 100% rename from mdhelp/en/add-excelname.md rename to mdHelp/en/add-excelname.md diff --git a/mdhelp/en/add-exceltable.md b/mdHelp/en/add-exceltable.md similarity index 100% rename from mdhelp/en/add-exceltable.md rename to mdHelp/en/add-exceltable.md diff --git a/mdhelp/en/add-pivottable.md b/mdHelp/en/add-pivottable.md similarity index 100% rename from mdhelp/en/add-pivottable.md rename to mdHelp/en/add-pivottable.md diff --git a/mdhelp/en/add-worksheet.md b/mdHelp/en/add-worksheet.md similarity index 100% rename from mdhelp/en/add-worksheet.md rename to mdHelp/en/add-worksheet.md diff --git a/mdhelp/en/close-excelpackage.md b/mdHelp/en/close-excelpackage.md similarity index 100% rename from mdhelp/en/close-excelpackage.md rename to mdHelp/en/close-excelpackage.md diff --git a/mdhelp/en/compare-worksheet.md b/mdHelp/en/compare-worksheet.md similarity index 100% rename from mdhelp/en/compare-worksheet.md rename to mdHelp/en/compare-worksheet.md diff --git a/mdhelp/en/convert-excelrangetoimage.md b/mdHelp/en/convert-excelrangetoimage.md similarity index 100% rename from mdhelp/en/convert-excelrangetoimage.md rename to mdHelp/en/convert-excelrangetoimage.md diff --git a/mdhelp/en/convertfrom-excelsheet.md b/mdHelp/en/convertfrom-excelsheet.md similarity index 100% rename from mdhelp/en/convertfrom-excelsheet.md rename to mdHelp/en/convertfrom-excelsheet.md diff --git a/mdhelp/en/convertfrom-exceltosqlinsert.md b/mdHelp/en/convertfrom-exceltosqlinsert.md similarity index 100% rename from mdhelp/en/convertfrom-exceltosqlinsert.md rename to mdHelp/en/convertfrom-exceltosqlinsert.md diff --git a/mdhelp/en/copy-excelworksheet.md b/mdHelp/en/copy-excelworksheet.md similarity index 100% rename from mdhelp/en/copy-excelworksheet.md rename to mdHelp/en/copy-excelworksheet.md diff --git a/mdhelp/en/expand-numberformat.md b/mdHelp/en/expand-numberformat.md similarity index 100% rename from mdhelp/en/expand-numberformat.md rename to mdHelp/en/expand-numberformat.md diff --git a/mdhelp/en/export-excel.md b/mdHelp/en/export-excel.md similarity index 100% rename from mdhelp/en/export-excel.md rename to mdHelp/en/export-excel.md diff --git a/mdhelp/en/get-excelsheetinfo.md b/mdHelp/en/get-excelsheetinfo.md similarity index 100% rename from mdhelp/en/get-excelsheetinfo.md rename to mdHelp/en/get-excelsheetinfo.md diff --git a/mdhelp/en/get-excelworkbookinfo.md b/mdHelp/en/get-excelworkbookinfo.md similarity index 100% rename from mdhelp/en/get-excelworkbookinfo.md rename to mdHelp/en/get-excelworkbookinfo.md diff --git a/mdhelp/en/import-excel.md b/mdHelp/en/import-excel.md similarity index 100% rename from mdhelp/en/import-excel.md rename to mdHelp/en/import-excel.md diff --git a/mdhelp/en/join-worksheet.md b/mdHelp/en/join-worksheet.md similarity index 100% rename from mdhelp/en/join-worksheet.md rename to mdHelp/en/join-worksheet.md diff --git a/mdhelp/en/merge-multiplesheets.md b/mdHelp/en/merge-multiplesheets.md similarity index 100% rename from mdhelp/en/merge-multiplesheets.md rename to mdHelp/en/merge-multiplesheets.md diff --git a/mdhelp/en/merge-worksheet.md b/mdHelp/en/merge-worksheet.md similarity index 100% rename from mdhelp/en/merge-worksheet.md rename to mdHelp/en/merge-worksheet.md diff --git a/mdhelp/en/new-conditionalformattingiconset.md b/mdHelp/en/new-conditionalformattingiconset.md similarity index 100% rename from mdhelp/en/new-conditionalformattingiconset.md rename to mdHelp/en/new-conditionalformattingiconset.md diff --git a/mdhelp/en/new-conditionaltext.md b/mdHelp/en/new-conditionaltext.md similarity index 100% rename from mdhelp/en/new-conditionaltext.md rename to mdHelp/en/new-conditionaltext.md diff --git a/mdhelp/en/new-excelchartdefinition.md b/mdHelp/en/new-excelchartdefinition.md similarity index 100% rename from mdhelp/en/new-excelchartdefinition.md rename to mdHelp/en/new-excelchartdefinition.md diff --git a/mdhelp/en/new-pivottabledefinition.md b/mdHelp/en/new-pivottabledefinition.md similarity index 100% rename from mdhelp/en/new-pivottabledefinition.md rename to mdHelp/en/new-pivottabledefinition.md diff --git a/mdhelp/en/open-excelpackage.md b/mdHelp/en/open-excelpackage.md similarity index 100% rename from mdhelp/en/open-excelpackage.md rename to mdHelp/en/open-excelpackage.md diff --git a/mdhelp/en/remove-worksheet.md b/mdHelp/en/remove-worksheet.md similarity index 100% rename from mdhelp/en/remove-worksheet.md rename to mdHelp/en/remove-worksheet.md diff --git a/mdhelp/en/select-worksheet.md b/mdHelp/en/select-worksheet.md similarity index 100% rename from mdhelp/en/select-worksheet.md rename to mdHelp/en/select-worksheet.md diff --git a/mdhelp/en/send-sqldatatoexcel.md b/mdHelp/en/send-sqldatatoexcel.md similarity index 100% rename from mdhelp/en/send-sqldatatoexcel.md rename to mdHelp/en/send-sqldatatoexcel.md diff --git a/mdhelp/en/set-excelcolumn.md b/mdHelp/en/set-excelcolumn.md similarity index 100% rename from mdhelp/en/set-excelcolumn.md rename to mdHelp/en/set-excelcolumn.md diff --git a/mdhelp/en/set-excelrange.md b/mdHelp/en/set-excelrange.md similarity index 100% rename from mdhelp/en/set-excelrange.md rename to mdHelp/en/set-excelrange.md diff --git a/mdhelp/en/set-excelrow.md b/mdHelp/en/set-excelrow.md similarity index 100% rename from mdhelp/en/set-excelrow.md rename to mdHelp/en/set-excelrow.md diff --git a/mdhelp/en/update-firstobjectproperties.md b/mdHelp/en/update-firstobjectproperties.md similarity index 100% rename from mdhelp/en/update-firstobjectproperties.md rename to mdHelp/en/update-firstobjectproperties.md From cb7f2a06f49eeeb47b8e463fee8529b0db38dd6d Mon Sep 17 00:00:00 2001 From: Doug Finke Date: Sun, 6 Mar 2022 14:52:37 -0500 Subject: [PATCH 089/140] Remove vscode badge --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index c598c42..2043afe 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,6 @@ Automate Excel via PowerShell without having Excel installed. Runs on Windows, L
-Open `ImportExcel` as a remote repo in VS Code, without cloning it. - -[![Open in Visual Studio Code](https://open.vscode.dev/badges/open-in-vscode.svg)](https://open.vscode.dev/dfinke/importexcel) - -
- | CI System | Environment | Status | | :--- | :--- | :--- | | Azure DevOps | Windows | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=Windows)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) | From 96493e059bb804e06a7a4abbed8a63722408ffe4 Mon Sep 17 00:00:00 2001 From: James Mueller <97551379+jamesmmueller@users.noreply.github.com> Date: Fri, 11 Mar 2022 16:09:38 -0600 Subject: [PATCH 090/140] ConvertFrom-ExcelToSQLInsert fix single quotes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If data in the Excel file contains single quotes, then the insert will bomb as it will be malformed. Quotes would need escaped. Not all languages will support the same escape method, so I recommend it being set by an optional parameter. Example of what will fail: Name ----------- Fry's INSERT INTO [Name] Values ( 'Fry's' ) Corrected for quotes (such as needing to escape a single quote with an additional single quote) INSERT INTO [Name] Values ('Fry''s') Example code: $ConvertToSqlParams = @{TableName = ‘dbo.Names’ Path = ‘C:\temp\data.xlsx’ ConvertEmptyStringsToNull = $true UseMSSQLSyntax = $true SingleQuoteStyle = "''" } $SQLInsert = ConvertFrom-ExcelToSqlInsert @ConvertToSqlParams --- Public/ConvertFrom-ExcelToSQLInsert.ps1 | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Public/ConvertFrom-ExcelToSQLInsert.ps1 b/Public/ConvertFrom-ExcelToSQLInsert.ps1 index b468d8b..858544e 100644 --- a/Public/ConvertFrom-ExcelToSQLInsert.ps1 +++ b/Public/ConvertFrom-ExcelToSQLInsert.ps1 @@ -16,12 +16,15 @@ function ConvertFrom-ExcelToSQLInsert { [switch]$NoHeader, [switch]$DataOnly, [switch]$ConvertEmptyStringsToNull, - [switch]$UseMsSqlSyntax + [switch]$UseMsSqlSyntax, + [Parameter(Mandatory = $false)] + $SingleQuoteStyle ) $null = $PSBoundParameters.Remove('TableName') $null = $PSBoundParameters.Remove('ConvertEmptyStringsToNull') $null = $PSBoundParameters.Remove('UseMsSqlSyntax') + $null = $PSBoundParameters.Remove('SingleQuoteStyle') $params = @{} + $PSBoundParameters @@ -38,11 +41,16 @@ function ConvertFrom-ExcelToSQLInsert { 'NULL' } else { - "'" + $record.$propertyName + "'" + if ( $SingleQuoteStyle ) { + "'" + $record.$propertyName.ToString().Replace("'",${SingleQuoteStyle}) + "'" + } + else { + "'" + $record.$propertyName + "'" + } } } $targetValues = ($values -join ", ") "INSERT INTO {0} ({1}) Values({2});" -f $TableName, $ColumnNames, $targetValues } -} \ No newline at end of file +} From 67ac63ddcf819f78645b3984cc1438202e9a0509 Mon Sep 17 00:00:00 2001 From: Craig Osborn Date: Fri, 25 Mar 2022 08:35:13 +0000 Subject: [PATCH 091/140] examples: Add VBA to single worksheet --- Examples/VBA/AddWorksheetVBA.ps1 | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Examples/VBA/AddWorksheetVBA.ps1 diff --git a/Examples/VBA/AddWorksheetVBA.ps1 b/Examples/VBA/AddWorksheetVBA.ps1 new file mode 100644 index 0000000..3068c41 --- /dev/null +++ b/Examples/VBA/AddWorksheetVBA.ps1 @@ -0,0 +1,41 @@ +$xlfile = "$env:temp\test.xlsm" +Remove-Item $xlfile -ErrorAction SilentlyContinue + +$Excel = ConvertFrom-Csv @" +Region,Item,TotalSold +West,screwdriver,98 +West,kiwi,19 +North,kiwi,47 +West,screws,48 +West,avocado,52 +East,avocado,40 +South,drill,61 +North,orange,92 +South,drill,29 +South,saw,36 +"@ | Export-Excel $xlfile -TableName 'Sales' -WorksheetName 'Sales' -AutoSize -PassThru + +$wb = $Excel.Workbook +$sheet = $wb.Worksheets["Sales"] +$wb.CreateVBAProject() + +# Add a sub to the 'Worksheet_SelectionChange' event of the worksheet to highlight the selected row & column of the active table. +# https://docs.microsoft.com/en-gb/office/vba/excel/Concepts/Cells-and-Ranges/highlight-the-active-cell-row-or-column +$code = @" +Private Sub Worksheet_SelectionChange(ByVal Target As Range) + ' Clear the color of all the cells + Cells.Interior.ColorIndex = 0 + If Target.Cells.Count > 1 Then Exit Sub + Application.ScreenUpdating = False + With ActiveCell + ' Highlight the row and column that contain the active cell, within the current region + Range(Cells(.Row, .CurrentRegion.Column), Cells(.Row, .CurrentRegion.Columns.Count + .CurrentRegion.Column - 1)).Interior.ColorIndex = 38 + Range(Cells(.CurrentRegion.Row, .Column), Cells(.CurrentRegion.Rows.Count + .CurrentRegion.Row - 1, .Column)).Interior.ColorIndex = 24 + End With + Application.ScreenUpdating = True +End Sub +"@ + +$sheet.CodeModule.Code = $code + +Close-ExcelPackage $Excel -Show \ No newline at end of file From 29ea7012d7e99c0e2821d9bde7361b458455c957 Mon Sep 17 00:00:00 2001 From: Craig Osborn Date: Fri, 25 Mar 2022 08:36:02 +0000 Subject: [PATCH 092/140] examples: Add VBA module and call in all worksheets --- Examples/VBA/AddModuleMultpleWorksheetVBA.ps1 | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Examples/VBA/AddModuleMultpleWorksheetVBA.ps1 diff --git a/Examples/VBA/AddModuleMultpleWorksheetVBA.ps1 b/Examples/VBA/AddModuleMultpleWorksheetVBA.ps1 new file mode 100644 index 0000000..456a9ed --- /dev/null +++ b/Examples/VBA/AddModuleMultpleWorksheetVBA.ps1 @@ -0,0 +1,64 @@ +$xlfile = "$env:temp\test.xlsm" +Remove-Item $xlfile -ErrorAction SilentlyContinue + +ConvertFrom-Csv @" +Region,Item,TotalSold +West,screwdriver,98 +West,kiwi,19 +North,kiwi,47 +West,screws,48 +West,avocado,52 +East,avocado,40 +South,drill,61 +North,orange,92 +South,drill,29 +South,saw,36 +"@ | Export-Excel $xlfile -TableName 'Sales' -WorksheetName 'Sales' -AutoSize + +$Excel = ConvertFrom-Csv @" +Supplier,Item,TotalBought +Hardware,screwdriver,98 +Groceries,kiwi,19 +Hardware,screws,48 +Groceries,avocado,52 +Hardware,drill,61 +Groceries,orange,92 +Hardware,drill,29 +HArdware,saw,36 +"@ | Export-Excel $xlfile -TableName 'Purchases' -WorksheetName 'Purchases' -PassThru -AutoSize + +$wb = $Excel.Workbook +$wb.CreateVBAProject() + +# Create a module with a sub to highlight the selected row & column of the active table. +# https://docs.microsoft.com/en-gb/office/vba/excel/Concepts/Cells-and-Ranges/highlight-the-active-cell-row-or-column +$codeModule = @" +Public Sub HighlightSelection(ByVal Target As Range) + ' Clear the color of all the cells + Cells.Interior.ColorIndex = 0 + If Target.Cells.Count > 1 Then Exit Sub + Application.ScreenUpdating = False + With ActiveCell + ' Highlight the row and column that contain the active cell, within the current region + Range(Cells(.Row, .CurrentRegion.Column), Cells(.Row, .CurrentRegion.Columns.Count + .CurrentRegion.Column - 1)).Interior.ColorIndex = 38 + Range(Cells(.CurrentRegion.Row, .Column), Cells(.CurrentRegion.Rows.Count + .CurrentRegion.Row - 1, .Column)).Interior.ColorIndex = 24 + End With + Application.ScreenUpdating = True +End Sub +"@ + +$module = $wb.VbaProject.Modules.AddModule("PSExcelModule") +$module.Code = $codeModule + +# Add a call to the row & column highlight sub on each worksheet. +$codeSheet = @" +Private Sub Worksheet_SelectionChange(ByVal Target As Range) + HighlightSelection Target +End Sub +"@ + +foreach ($sheet in $wb.Worksheets) { + $sheet.CodeModule.Code = $codeSheet +} + +Close-ExcelPackage $Excel -Show \ No newline at end of file From 441f2ada226005792068056738a14d1cde1a5ab3 Mon Sep 17 00:00:00 2001 From: Craig Osborn Date: Fri, 25 Mar 2022 08:43:48 +0000 Subject: [PATCH 093/140] fix: Typo in filename --- ...eMultpleWorksheetVBA.ps1 => AddModuleMultipleWorksheetVBA.ps1} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Examples/VBA/{AddModuleMultpleWorksheetVBA.ps1 => AddModuleMultipleWorksheetVBA.ps1} (100%) diff --git a/Examples/VBA/AddModuleMultpleWorksheetVBA.ps1 b/Examples/VBA/AddModuleMultipleWorksheetVBA.ps1 similarity index 100% rename from Examples/VBA/AddModuleMultpleWorksheetVBA.ps1 rename to Examples/VBA/AddModuleMultipleWorksheetVBA.ps1 From 606988bcf6ad2cce25ae20976bdbf528f2b285df Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 25 Mar 2022 18:45:06 -0400 Subject: [PATCH 094/140] rigger build --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2043afe..b614b3b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # PowerShell + Excel = Better Together + Automate Excel via PowerShell without having Excel installed. Runs on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier.
From 34f55a36599751bd3427a6a111a63f180eb91b65 Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 25 Mar 2022 19:32:53 -0400 Subject: [PATCH 095/140] suspect Get-Service --- __tests__/RangePassing.Tests.ps1 | 224 +++++++++++++++---------------- 1 file changed, 112 insertions(+), 112 deletions(-) diff --git a/__tests__/RangePassing.Tests.ps1 b/__tests__/RangePassing.Tests.ps1 index bb460b5..6d697cf 100644 --- a/__tests__/RangePassing.Tests.ps1 +++ b/__tests__/RangePassing.Tests.ps1 @@ -4,121 +4,121 @@ param() describe "Consistent passing of ranges." { - BeforeAll { - $path = "TestDrive:\test.xlsx" - if (-not (Get-command Get-Service -ErrorAction SilentlyContinue)) { - Function Get-Service {Import-Clixml $PSScriptRoot\Mockservices.xml} - } - } - Context "Conditional Formatting" { - it "accepts named ranges, cells['name'], worksheet + Name, worksheet + column " { - Remove-Item -path $path -ErrorAction SilentlyContinue - $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -AutoNameRange -Title "Services on $Env:COMPUTERNAME" - {Add-ConditionalFormatting $excel.Services.Names["Status"] -StrikeThru -RuleType ContainsText -ConditionValue "Stopped" } | Should -Not -Throw - $excel.Services.ConditionalFormatting.Count | Should -Be 1 - {Add-ConditionalFormatting $excel.Services.Cells["Name"] -Italic -RuleType ContainsText -ConditionValue "SVC" } | Should -Not -Throw - $excel.Services.ConditionalFormatting.Count | Should -Be 2 - $warnvar = $null - Add-ConditionalFormatting $excel.Services.Column(3) ` - -underline -RuleType ContainsText -ConditionValue "Windows" -WarningVariable warnvar -WarningAction SilentlyContinue - $warnvar | Should -Not -BeNullOrEmpty - $excel.Services.ConditionalFormatting.Count | Should -Be 2 - $warnvar = $null - Add-ConditionalFormatting $excel.Services.Column(3) -Worksheet $excel.Services` - -underline -RuleType ContainsText -ConditionValue "Windows" -WarningVariable warnvar -WarningAction SilentlyContinue - $warnvar | Should -BeNullOrEmpty - $excel.Services.ConditionalFormatting.Count | Should -Be 3 - {Add-ConditionalFormatting "Status" -Worksheet $excel.Services ` - -ForeGroundColor ([System.Drawing.Color]::Green) -RuleType ContainsText -ConditionValue "Running"} | Should -Not -Throw - $excel.Services.ConditionalFormatting.Count | Should -Be 4 - Close-ExcelPackage -NoSave $excel - } + # BeforeAll { + # $path = "TestDrive:\test.xlsx" + # if (-not (Get-command Get-Service -ErrorAction SilentlyContinue)) { + # Function Get-Service {Import-Clixml $PSScriptRoot\Mockservices.xml} + # } + # } + # Context "Conditional Formatting" { + # it "accepts named ranges, cells['name'], worksheet + Name, worksheet + column " { + # Remove-Item -path $path -ErrorAction SilentlyContinue + # $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -AutoNameRange -Title "Services on $Env:COMPUTERNAME" + # {Add-ConditionalFormatting $excel.Services.Names["Status"] -StrikeThru -RuleType ContainsText -ConditionValue "Stopped" } | Should -Not -Throw + # $excel.Services.ConditionalFormatting.Count | Should -Be 1 + # {Add-ConditionalFormatting $excel.Services.Cells["Name"] -Italic -RuleType ContainsText -ConditionValue "SVC" } | Should -Not -Throw + # $excel.Services.ConditionalFormatting.Count | Should -Be 2 + # $warnvar = $null + # Add-ConditionalFormatting $excel.Services.Column(3) ` + # -underline -RuleType ContainsText -ConditionValue "Windows" -WarningVariable warnvar -WarningAction SilentlyContinue + # $warnvar | Should -Not -BeNullOrEmpty + # $excel.Services.ConditionalFormatting.Count | Should -Be 2 + # $warnvar = $null + # Add-ConditionalFormatting $excel.Services.Column(3) -Worksheet $excel.Services` + # -underline -RuleType ContainsText -ConditionValue "Windows" -WarningVariable warnvar -WarningAction SilentlyContinue + # $warnvar | Should -BeNullOrEmpty + # $excel.Services.ConditionalFormatting.Count | Should -Be 3 + # {Add-ConditionalFormatting "Status" -Worksheet $excel.Services ` + # -ForeGroundColor ([System.Drawing.Color]::Green) -RuleType ContainsText -ConditionValue "Running"} | Should -Not -Throw + # $excel.Services.ConditionalFormatting.Count | Should -Be 4 + # Close-ExcelPackage -NoSave $excel + # } - it "accepts table, table.Address and worksheet + 'C:C' " { - $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" - {Add-ConditionalFormatting $excel.Services.Tables[0] ` - -Italic -RuleType ContainsText -ConditionValue "Svc" } | Should -Not -Throw - $excel.Services.ConditionalFormatting.Count | Should -Be 1 - {Add-ConditionalFormatting $excel.Services.Tables["ServiceTable"].Address ` - -Bold -RuleType ContainsText -ConditionValue "windows" } | Should -Not -Throw - $excel.Services.ConditionalFormatting.Count | Should -Be 2 - {Add-ConditionalFormatting -Worksheet $excel.Services -Address "a:a" ` - -RuleType ContainsText -ConditionValue "stopped" -ForeGroundColor ([System.Drawing.Color]::Red) } | Should -Not -Throw - $excel.Services.ConditionalFormatting.Count | Should -Be 3 - Close-ExcelPackage -NoSave $excel - } - } + # it "accepts table, table.Address and worksheet + 'C:C' " { + # $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" + # {Add-ConditionalFormatting $excel.Services.Tables[0] ` + # -Italic -RuleType ContainsText -ConditionValue "Svc" } | Should -Not -Throw + # $excel.Services.ConditionalFormatting.Count | Should -Be 1 + # {Add-ConditionalFormatting $excel.Services.Tables["ServiceTable"].Address ` + # -Bold -RuleType ContainsText -ConditionValue "windows" } | Should -Not -Throw + # $excel.Services.ConditionalFormatting.Count | Should -Be 2 + # {Add-ConditionalFormatting -Worksheet $excel.Services -Address "a:a" ` + # -RuleType ContainsText -ConditionValue "stopped" -ForeGroundColor ([System.Drawing.Color]::Red) } | Should -Not -Throw + # $excel.Services.ConditionalFormatting.Count | Should -Be 3 + # Close-ExcelPackage -NoSave $excel + # } + # } - Context "Formating (Set-ExcelRange or its alias Set-Format) " { - it "accepts Named Range, cells['Name'], cells['A1:Z9'], row, Worksheet + 'A1:Z9'" { - $excel = Get-Service | Export-Excel -Path test2.xlsx -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -RangeName servicerange -Title "Services on $Env:COMPUTERNAME" - {Set-format $excel.Services.Names["serviceRange"] -Bold } | Should -Not -Throw - $excel.Services.cells["B2"].Style.Font.Bold | Should -Be $true - {Set-ExcelRange -Range $excel.Services.Cells["serviceRange"] -italic:$true } | Should -Not -Throw - $excel.Services.cells["C3"].Style.Font.Italic | Should -Be $true - {Set-format $excel.Services.Row(4) -underline -Bold:$false } | Should -Not -Throw - $excel.Services.cells["A4"].Style.Font.UnderLine | Should -Be $true - $excel.Services.cells["A4"].Style.Font.Bold | Should -Not -Be $true - {Set-ExcelRange $excel.Services.Cells["A3:B3"] -StrikeThru } | Should -Not -Throw - $excel.Services.cells["B3"].Style.Font.Strike | Should -Be $true - {Set-ExcelRange -Worksheet $excel.Services -Range "A5:B6" -FontSize 8 } | Should -Not -Throw - $excel.Services.cells["A5"].Style.Font.Size | Should -Be 8 - Close-ExcelPackage -NoSave $excel - } + # Context "Formating (Set-ExcelRange or its alias Set-Format) " { + # it "accepts Named Range, cells['Name'], cells['A1:Z9'], row, Worksheet + 'A1:Z9'" { + # $excel = Get-Service | Export-Excel -Path test2.xlsx -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -RangeName servicerange -Title "Services on $Env:COMPUTERNAME" + # {Set-format $excel.Services.Names["serviceRange"] -Bold } | Should -Not -Throw + # $excel.Services.cells["B2"].Style.Font.Bold | Should -Be $true + # {Set-ExcelRange -Range $excel.Services.Cells["serviceRange"] -italic:$true } | Should -Not -Throw + # $excel.Services.cells["C3"].Style.Font.Italic | Should -Be $true + # {Set-format $excel.Services.Row(4) -underline -Bold:$false } | Should -Not -Throw + # $excel.Services.cells["A4"].Style.Font.UnderLine | Should -Be $true + # $excel.Services.cells["A4"].Style.Font.Bold | Should -Not -Be $true + # {Set-ExcelRange $excel.Services.Cells["A3:B3"] -StrikeThru } | Should -Not -Throw + # $excel.Services.cells["B3"].Style.Font.Strike | Should -Be $true + # {Set-ExcelRange -Worksheet $excel.Services -Range "A5:B6" -FontSize 8 } | Should -Not -Throw + # $excel.Services.cells["A5"].Style.Font.Size | Should -Be 8 + # Close-ExcelPackage -NoSave $excel + # } - it "Accepts Table, Table.Address , worksheet + Name, Column," { - $excel = Get-Service | Export-Excel -Path test2.xlsx -WorksheetName Services -PassThru -AutoNameRange -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" - {Set-ExcelRange $excel.Services.Tables[0] -Italic } | Should -Not -Throw - $excel.Services.cells["C3"].Style.Font.Italic | Should -Be $true - {Set-format $excel.Services.Tables["ServiceTable"].Address -Underline } | Should -Not -Throw - $excel.Services.cells["C3"].Style.Font.UnderLine | Should -Be $true - {Set-ExcelRange -Worksheet $excel.Services -Range "Name" -Bold } | Should -Not -Throw - $excel.Services.cells["B4"].Style.Font.Bold | Should -Be $true - {$excel.Services.Column(3) | Set-ExcelRange -FontColor ([System.Drawing.Color]::Red) } | Should -Not -Throw - $excel.Services.cells["C4"].Style.Font.Color.Rgb | Should -Be "FFFF0000" - Close-ExcelPackage -NoSave $excel - } + # it "Accepts Table, Table.Address , worksheet + Name, Column," { + # $excel = Get-Service | Export-Excel -Path test2.xlsx -WorksheetName Services -PassThru -AutoNameRange -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" + # {Set-ExcelRange $excel.Services.Tables[0] -Italic } | Should -Not -Throw + # $excel.Services.cells["C3"].Style.Font.Italic | Should -Be $true + # {Set-format $excel.Services.Tables["ServiceTable"].Address -Underline } | Should -Not -Throw + # $excel.Services.cells["C3"].Style.Font.UnderLine | Should -Be $true + # {Set-ExcelRange -Worksheet $excel.Services -Range "Name" -Bold } | Should -Not -Throw + # $excel.Services.cells["B4"].Style.Font.Bold | Should -Be $true + # {$excel.Services.Column(3) | Set-ExcelRange -FontColor ([System.Drawing.Color]::Red) } | Should -Not -Throw + # $excel.Services.cells["C4"].Style.Font.Color.Rgb | Should -Be "FFFF0000" + # Close-ExcelPackage -NoSave $excel + # } - } + # } - Context "PivotTables" { - it "Accepts Named range, .Cells['Name'], name&Worksheet, cells['A1:Z9'], worksheet&'A1:Z9' "{ - $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -RangeName servicerange -Title "Services on $Env:COMPUTERNAME" - $ws = $excel.Workbook.Worksheets[1] #can get a worksheet by name or index - starting at 1 - $end = $ws.Dimension.End.Address - #can get a named ranged by name or index - starting at zero - {Add-PivotTable -ExcelPackage $excel -PivotTableName pt0 -SourceRange $ws.Names[0]` - -PivotRows Status -PivotData Name } | Should -Not -Throw - $excel.Workbook.Worksheets["pt0"] | Should -Not -BeNullOrEmpty - {Add-PivotTable -ExcelPackage $excel -PivotTableName pt1 -SourceRange $ws.Names["servicerange"]` - -PivotRows Status -PivotData Name } | Should -Not -Throw - $excel.Workbook.Worksheets["pt1"] | Should -Not -BeNullOrEmpty - #Can specify the range for a pivot as NamedRange or Table or TableAddress or Worksheet + "A1:Z10" or worksheet + RangeName, or worksheet.cells["A1:Z10"] or worksheet.cells["RangeName"] - {Add-PivotTable -ExcelPackage $excel -PivotTableName pt2 -SourceRange "servicerange" -SourceWorkSheet $ws ` - -PivotRows Status -PivotData Name } | Should -Not -Throw - $excel.Workbook.Worksheets["pt2"] | Should -Not -BeNullOrEmpty - {Add-PivotTable -ExcelPackage $excel -PivotTableName pt3 -SourceRange $ws.cells["servicerange"]` - -PivotRows Status -PivotData Name } | Should -Not -Throw - $excel.Workbook.Worksheets["pt3"] | Should -Not -BeNullOrEmpty - {Add-PivotTable -ExcelPackage $excel -PivotTableName pt4 -SourceRange $ws.cells["A2:$end"]` - -PivotRows Status -PivotData Name } | Should -Not -Throw - $excel.Workbook.Worksheets["pt4"] | Should -Not -BeNullOrEmpty - {Add-PivotTable -ExcelPackage $excel -PivotTableName pt5 -SourceRange "A2:$end" -SourceWorkSheet $ws ` - -PivotRows Status -PivotData Name } | Should -Not -Throw - $excel.Workbook.Worksheets["pt5"] | Should -Not -BeNullOrEmpty - Close-ExcelPackage -NoSave $excel - } - it "Accepts Table, Table.Addres " { - $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" - $ws = $excel.Workbook.Worksheets["Services"] #can get a worksheet by name or index - starting at 1 - #Can get a table by name or -stating at zero. Can specify the range for a pivot as or Table or TableAddress - {Add-PivotTable -ExcelPackage $excel -PivotTableName pt1 -SourceRange $ws.tables["servicetable"]` - -PivotRows Status -PivotData Name } | Should -Not -Throw - $excel.Workbook.Worksheets["pt1"] | Should -Not -BeNullOrEmpty - {Add-PivotTable -ExcelPackage $excel -PivotTableName pt2 -SourceRange $ws.tables[0].Address ` - -PivotRows Status -PivotData Name } | Should -Not -Throw - $excel.Workbook.Worksheets["pt2"] | Should -Not -BeNullOrEmpty - Close-ExcelPackage -NoSave $excel - } - } + # Context "PivotTables" { + # it "Accepts Named range, .Cells['Name'], name&Worksheet, cells['A1:Z9'], worksheet&'A1:Z9' "{ + # $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -RangeName servicerange -Title "Services on $Env:COMPUTERNAME" + # $ws = $excel.Workbook.Worksheets[1] #can get a worksheet by name or index - starting at 1 + # $end = $ws.Dimension.End.Address + # #can get a named ranged by name or index - starting at zero + # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt0 -SourceRange $ws.Names[0]` + # -PivotRows Status -PivotData Name } | Should -Not -Throw + # $excel.Workbook.Worksheets["pt0"] | Should -Not -BeNullOrEmpty + # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt1 -SourceRange $ws.Names["servicerange"]` + # -PivotRows Status -PivotData Name } | Should -Not -Throw + # $excel.Workbook.Worksheets["pt1"] | Should -Not -BeNullOrEmpty + # #Can specify the range for a pivot as NamedRange or Table or TableAddress or Worksheet + "A1:Z10" or worksheet + RangeName, or worksheet.cells["A1:Z10"] or worksheet.cells["RangeName"] + # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt2 -SourceRange "servicerange" -SourceWorkSheet $ws ` + # -PivotRows Status -PivotData Name } | Should -Not -Throw + # $excel.Workbook.Worksheets["pt2"] | Should -Not -BeNullOrEmpty + # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt3 -SourceRange $ws.cells["servicerange"]` + # -PivotRows Status -PivotData Name } | Should -Not -Throw + # $excel.Workbook.Worksheets["pt3"] | Should -Not -BeNullOrEmpty + # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt4 -SourceRange $ws.cells["A2:$end"]` + # -PivotRows Status -PivotData Name } | Should -Not -Throw + # $excel.Workbook.Worksheets["pt4"] | Should -Not -BeNullOrEmpty + # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt5 -SourceRange "A2:$end" -SourceWorkSheet $ws ` + # -PivotRows Status -PivotData Name } | Should -Not -Throw + # $excel.Workbook.Worksheets["pt5"] | Should -Not -BeNullOrEmpty + # Close-ExcelPackage -NoSave $excel + # } + # it "Accepts Table, Table.Addres " { + # $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" + # $ws = $excel.Workbook.Worksheets["Services"] #can get a worksheet by name or index - starting at 1 + # #Can get a table by name or -stating at zero. Can specify the range for a pivot as or Table or TableAddress + # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt1 -SourceRange $ws.tables["servicetable"]` + # -PivotRows Status -PivotData Name } | Should -Not -Throw + # $excel.Workbook.Worksheets["pt1"] | Should -Not -BeNullOrEmpty + # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt2 -SourceRange $ws.tables[0].Address ` + # -PivotRows Status -PivotData Name } | Should -Not -Throw + # $excel.Workbook.Worksheets["pt2"] | Should -Not -BeNullOrEmpty + # Close-ExcelPackage -NoSave $excel + # } + # } } \ No newline at end of file From d7901af8f3e6d5e77a9a08b539cc869bfddd7a0a Mon Sep 17 00:00:00 2001 From: dfinke Date: Sun, 27 Mar 2022 09:37:15 -0400 Subject: [PATCH 096/140] try always importing the clixml --- __tests__/RangePassing.Tests.ps1 | 228 +++++++++++++++---------------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/__tests__/RangePassing.Tests.ps1 b/__tests__/RangePassing.Tests.ps1 index 6d697cf..0d44121 100644 --- a/__tests__/RangePassing.Tests.ps1 +++ b/__tests__/RangePassing.Tests.ps1 @@ -1,124 +1,124 @@ #Requires -Modules Pester -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments','',Justification='False Positives')] -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases','',Justification='Testing for presence of alias')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'False Positives')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '', Justification = 'Testing for presence of alias')] param() describe "Consistent passing of ranges." { - # BeforeAll { - # $path = "TestDrive:\test.xlsx" - # if (-not (Get-command Get-Service -ErrorAction SilentlyContinue)) { - # Function Get-Service {Import-Clixml $PSScriptRoot\Mockservices.xml} - # } - # } - # Context "Conditional Formatting" { - # it "accepts named ranges, cells['name'], worksheet + Name, worksheet + column " { - # Remove-Item -path $path -ErrorAction SilentlyContinue - # $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -AutoNameRange -Title "Services on $Env:COMPUTERNAME" - # {Add-ConditionalFormatting $excel.Services.Names["Status"] -StrikeThru -RuleType ContainsText -ConditionValue "Stopped" } | Should -Not -Throw - # $excel.Services.ConditionalFormatting.Count | Should -Be 1 - # {Add-ConditionalFormatting $excel.Services.Cells["Name"] -Italic -RuleType ContainsText -ConditionValue "SVC" } | Should -Not -Throw - # $excel.Services.ConditionalFormatting.Count | Should -Be 2 - # $warnvar = $null - # Add-ConditionalFormatting $excel.Services.Column(3) ` - # -underline -RuleType ContainsText -ConditionValue "Windows" -WarningVariable warnvar -WarningAction SilentlyContinue - # $warnvar | Should -Not -BeNullOrEmpty - # $excel.Services.ConditionalFormatting.Count | Should -Be 2 - # $warnvar = $null - # Add-ConditionalFormatting $excel.Services.Column(3) -Worksheet $excel.Services` - # -underline -RuleType ContainsText -ConditionValue "Windows" -WarningVariable warnvar -WarningAction SilentlyContinue - # $warnvar | Should -BeNullOrEmpty - # $excel.Services.ConditionalFormatting.Count | Should -Be 3 - # {Add-ConditionalFormatting "Status" -Worksheet $excel.Services ` - # -ForeGroundColor ([System.Drawing.Color]::Green) -RuleType ContainsText -ConditionValue "Running"} | Should -Not -Throw - # $excel.Services.ConditionalFormatting.Count | Should -Be 4 - # Close-ExcelPackage -NoSave $excel - # } + BeforeAll { + $path = "TestDrive:\test.xlsx" + # if (-not (Get-command Get-Service -ErrorAction SilentlyContinue)) { + Function Get-Service { Import-Clixml $PSScriptRoot\Mockservices.xml } + # } + } + Context "Conditional Formatting" { + it "accepts named ranges, cells['name'], worksheet + Name, worksheet + column " { + Remove-Item -path $path -ErrorAction SilentlyContinue + $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -AutoNameRange -Title "Services on $Env:COMPUTERNAME" + { Add-ConditionalFormatting $excel.Services.Names["Status"] -StrikeThru -RuleType ContainsText -ConditionValue "Stopped" } | Should -Not -Throw + $excel.Services.ConditionalFormatting.Count | Should -Be 1 + { Add-ConditionalFormatting $excel.Services.Cells["Name"] -Italic -RuleType ContainsText -ConditionValue "SVC" } | Should -Not -Throw + $excel.Services.ConditionalFormatting.Count | Should -Be 2 + $warnvar = $null + Add-ConditionalFormatting $excel.Services.Column(3) ` + -underline -RuleType ContainsText -ConditionValue "Windows" -WarningVariable warnvar -WarningAction SilentlyContinue + $warnvar | Should -Not -BeNullOrEmpty + $excel.Services.ConditionalFormatting.Count | Should -Be 2 + $warnvar = $null + Add-ConditionalFormatting $excel.Services.Column(3) -Worksheet $excel.Services` + -underline -RuleType ContainsText -ConditionValue "Windows" -WarningVariable warnvar -WarningAction SilentlyContinue + $warnvar | Should -BeNullOrEmpty + $excel.Services.ConditionalFormatting.Count | Should -Be 3 + { Add-ConditionalFormatting "Status" -Worksheet $excel.Services ` + -ForeGroundColor ([System.Drawing.Color]::Green) -RuleType ContainsText -ConditionValue "Running" } | Should -Not -Throw + $excel.Services.ConditionalFormatting.Count | Should -Be 4 + Close-ExcelPackage -NoSave $excel + } - # it "accepts table, table.Address and worksheet + 'C:C' " { - # $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" - # {Add-ConditionalFormatting $excel.Services.Tables[0] ` - # -Italic -RuleType ContainsText -ConditionValue "Svc" } | Should -Not -Throw - # $excel.Services.ConditionalFormatting.Count | Should -Be 1 - # {Add-ConditionalFormatting $excel.Services.Tables["ServiceTable"].Address ` - # -Bold -RuleType ContainsText -ConditionValue "windows" } | Should -Not -Throw - # $excel.Services.ConditionalFormatting.Count | Should -Be 2 - # {Add-ConditionalFormatting -Worksheet $excel.Services -Address "a:a" ` - # -RuleType ContainsText -ConditionValue "stopped" -ForeGroundColor ([System.Drawing.Color]::Red) } | Should -Not -Throw - # $excel.Services.ConditionalFormatting.Count | Should -Be 3 - # Close-ExcelPackage -NoSave $excel - # } - # } + it "accepts table, table.Address and worksheet + 'C:C' " { + $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" + { Add-ConditionalFormatting $excel.Services.Tables[0] ` + -Italic -RuleType ContainsText -ConditionValue "Svc" } | Should -Not -Throw + $excel.Services.ConditionalFormatting.Count | Should -Be 1 + { Add-ConditionalFormatting $excel.Services.Tables["ServiceTable"].Address ` + -Bold -RuleType ContainsText -ConditionValue "windows" } | Should -Not -Throw + $excel.Services.ConditionalFormatting.Count | Should -Be 2 + { Add-ConditionalFormatting -Worksheet $excel.Services -Address "a:a" ` + -RuleType ContainsText -ConditionValue "stopped" -ForeGroundColor ([System.Drawing.Color]::Red) } | Should -Not -Throw + $excel.Services.ConditionalFormatting.Count | Should -Be 3 + Close-ExcelPackage -NoSave $excel + } + } - # Context "Formating (Set-ExcelRange or its alias Set-Format) " { - # it "accepts Named Range, cells['Name'], cells['A1:Z9'], row, Worksheet + 'A1:Z9'" { - # $excel = Get-Service | Export-Excel -Path test2.xlsx -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -RangeName servicerange -Title "Services on $Env:COMPUTERNAME" - # {Set-format $excel.Services.Names["serviceRange"] -Bold } | Should -Not -Throw - # $excel.Services.cells["B2"].Style.Font.Bold | Should -Be $true - # {Set-ExcelRange -Range $excel.Services.Cells["serviceRange"] -italic:$true } | Should -Not -Throw - # $excel.Services.cells["C3"].Style.Font.Italic | Should -Be $true - # {Set-format $excel.Services.Row(4) -underline -Bold:$false } | Should -Not -Throw - # $excel.Services.cells["A4"].Style.Font.UnderLine | Should -Be $true - # $excel.Services.cells["A4"].Style.Font.Bold | Should -Not -Be $true - # {Set-ExcelRange $excel.Services.Cells["A3:B3"] -StrikeThru } | Should -Not -Throw - # $excel.Services.cells["B3"].Style.Font.Strike | Should -Be $true - # {Set-ExcelRange -Worksheet $excel.Services -Range "A5:B6" -FontSize 8 } | Should -Not -Throw - # $excel.Services.cells["A5"].Style.Font.Size | Should -Be 8 - # Close-ExcelPackage -NoSave $excel - # } + Context "Formating (Set-ExcelRange or its alias Set-Format) " { + it "accepts Named Range, cells['Name'], cells['A1:Z9'], row, Worksheet + 'A1:Z9'" { + $excel = Get-Service | Export-Excel -Path test2.xlsx -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -RangeName servicerange -Title "Services on $Env:COMPUTERNAME" + { Set-format $excel.Services.Names["serviceRange"] -Bold } | Should -Not -Throw + $excel.Services.cells["B2"].Style.Font.Bold | Should -Be $true + { Set-ExcelRange -Range $excel.Services.Cells["serviceRange"] -italic:$true } | Should -Not -Throw + $excel.Services.cells["C3"].Style.Font.Italic | Should -Be $true + { Set-format $excel.Services.Row(4) -underline -Bold:$false } | Should -Not -Throw + $excel.Services.cells["A4"].Style.Font.UnderLine | Should -Be $true + $excel.Services.cells["A4"].Style.Font.Bold | Should -Not -Be $true + { Set-ExcelRange $excel.Services.Cells["A3:B3"] -StrikeThru } | Should -Not -Throw + $excel.Services.cells["B3"].Style.Font.Strike | Should -Be $true + { Set-ExcelRange -Worksheet $excel.Services -Range "A5:B6" -FontSize 8 } | Should -Not -Throw + $excel.Services.cells["A5"].Style.Font.Size | Should -Be 8 + Close-ExcelPackage -NoSave $excel + } - # it "Accepts Table, Table.Address , worksheet + Name, Column," { - # $excel = Get-Service | Export-Excel -Path test2.xlsx -WorksheetName Services -PassThru -AutoNameRange -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" - # {Set-ExcelRange $excel.Services.Tables[0] -Italic } | Should -Not -Throw - # $excel.Services.cells["C3"].Style.Font.Italic | Should -Be $true - # {Set-format $excel.Services.Tables["ServiceTable"].Address -Underline } | Should -Not -Throw - # $excel.Services.cells["C3"].Style.Font.UnderLine | Should -Be $true - # {Set-ExcelRange -Worksheet $excel.Services -Range "Name" -Bold } | Should -Not -Throw - # $excel.Services.cells["B4"].Style.Font.Bold | Should -Be $true - # {$excel.Services.Column(3) | Set-ExcelRange -FontColor ([System.Drawing.Color]::Red) } | Should -Not -Throw - # $excel.Services.cells["C4"].Style.Font.Color.Rgb | Should -Be "FFFF0000" - # Close-ExcelPackage -NoSave $excel - # } + it "Accepts Table, Table.Address , worksheet + Name, Column," { + $excel = Get-Service | Export-Excel -Path test2.xlsx -WorksheetName Services -PassThru -AutoNameRange -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" + { Set-ExcelRange $excel.Services.Tables[0] -Italic } | Should -Not -Throw + $excel.Services.cells["C3"].Style.Font.Italic | Should -Be $true + { Set-format $excel.Services.Tables["ServiceTable"].Address -Underline } | Should -Not -Throw + $excel.Services.cells["C3"].Style.Font.UnderLine | Should -Be $true + { Set-ExcelRange -Worksheet $excel.Services -Range "Name" -Bold } | Should -Not -Throw + $excel.Services.cells["B4"].Style.Font.Bold | Should -Be $true + { $excel.Services.Column(3) | Set-ExcelRange -FontColor ([System.Drawing.Color]::Red) } | Should -Not -Throw + $excel.Services.cells["C4"].Style.Font.Color.Rgb | Should -Be "FFFF0000" + Close-ExcelPackage -NoSave $excel + } - # } + } - # Context "PivotTables" { - # it "Accepts Named range, .Cells['Name'], name&Worksheet, cells['A1:Z9'], worksheet&'A1:Z9' "{ - # $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -RangeName servicerange -Title "Services on $Env:COMPUTERNAME" - # $ws = $excel.Workbook.Worksheets[1] #can get a worksheet by name or index - starting at 1 - # $end = $ws.Dimension.End.Address - # #can get a named ranged by name or index - starting at zero - # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt0 -SourceRange $ws.Names[0]` - # -PivotRows Status -PivotData Name } | Should -Not -Throw - # $excel.Workbook.Worksheets["pt0"] | Should -Not -BeNullOrEmpty - # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt1 -SourceRange $ws.Names["servicerange"]` - # -PivotRows Status -PivotData Name } | Should -Not -Throw - # $excel.Workbook.Worksheets["pt1"] | Should -Not -BeNullOrEmpty - # #Can specify the range for a pivot as NamedRange or Table or TableAddress or Worksheet + "A1:Z10" or worksheet + RangeName, or worksheet.cells["A1:Z10"] or worksheet.cells["RangeName"] - # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt2 -SourceRange "servicerange" -SourceWorkSheet $ws ` - # -PivotRows Status -PivotData Name } | Should -Not -Throw - # $excel.Workbook.Worksheets["pt2"] | Should -Not -BeNullOrEmpty - # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt3 -SourceRange $ws.cells["servicerange"]` - # -PivotRows Status -PivotData Name } | Should -Not -Throw - # $excel.Workbook.Worksheets["pt3"] | Should -Not -BeNullOrEmpty - # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt4 -SourceRange $ws.cells["A2:$end"]` - # -PivotRows Status -PivotData Name } | Should -Not -Throw - # $excel.Workbook.Worksheets["pt4"] | Should -Not -BeNullOrEmpty - # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt5 -SourceRange "A2:$end" -SourceWorkSheet $ws ` - # -PivotRows Status -PivotData Name } | Should -Not -Throw - # $excel.Workbook.Worksheets["pt5"] | Should -Not -BeNullOrEmpty - # Close-ExcelPackage -NoSave $excel - # } - # it "Accepts Table, Table.Addres " { - # $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" - # $ws = $excel.Workbook.Worksheets["Services"] #can get a worksheet by name or index - starting at 1 - # #Can get a table by name or -stating at zero. Can specify the range for a pivot as or Table or TableAddress - # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt1 -SourceRange $ws.tables["servicetable"]` - # -PivotRows Status -PivotData Name } | Should -Not -Throw - # $excel.Workbook.Worksheets["pt1"] | Should -Not -BeNullOrEmpty - # {Add-PivotTable -ExcelPackage $excel -PivotTableName pt2 -SourceRange $ws.tables[0].Address ` - # -PivotRows Status -PivotData Name } | Should -Not -Throw - # $excel.Workbook.Worksheets["pt2"] | Should -Not -BeNullOrEmpty - # Close-ExcelPackage -NoSave $excel - # } - # } + Context "PivotTables" { + it "Accepts Named range, .Cells['Name'], name&Worksheet, cells['A1:Z9'], worksheet&'A1:Z9' " { + $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -RangeName servicerange -Title "Services on $Env:COMPUTERNAME" + $ws = $excel.Workbook.Worksheets[1] #can get a worksheet by name or index - starting at 1 + $end = $ws.Dimension.End.Address + #can get a named ranged by name or index - starting at zero + { Add-PivotTable -ExcelPackage $excel -PivotTableName pt0 -SourceRange $ws.Names[0]` + -PivotRows Status -PivotData Name } | Should -Not -Throw + $excel.Workbook.Worksheets["pt0"] | Should -Not -BeNullOrEmpty + { Add-PivotTable -ExcelPackage $excel -PivotTableName pt1 -SourceRange $ws.Names["servicerange"]` + -PivotRows Status -PivotData Name } | Should -Not -Throw + $excel.Workbook.Worksheets["pt1"] | Should -Not -BeNullOrEmpty + #Can specify the range for a pivot as NamedRange or Table or TableAddress or Worksheet + "A1:Z10" or worksheet + RangeName, or worksheet.cells["A1:Z10"] or worksheet.cells["RangeName"] + { Add-PivotTable -ExcelPackage $excel -PivotTableName pt2 -SourceRange "servicerange" -SourceWorkSheet $ws ` + -PivotRows Status -PivotData Name } | Should -Not -Throw + $excel.Workbook.Worksheets["pt2"] | Should -Not -BeNullOrEmpty + { Add-PivotTable -ExcelPackage $excel -PivotTableName pt3 -SourceRange $ws.cells["servicerange"]` + -PivotRows Status -PivotData Name } | Should -Not -Throw + $excel.Workbook.Worksheets["pt3"] | Should -Not -BeNullOrEmpty + { Add-PivotTable -ExcelPackage $excel -PivotTableName pt4 -SourceRange $ws.cells["A2:$end"]` + -PivotRows Status -PivotData Name } | Should -Not -Throw + $excel.Workbook.Worksheets["pt4"] | Should -Not -BeNullOrEmpty + { Add-PivotTable -ExcelPackage $excel -PivotTableName pt5 -SourceRange "A2:$end" -SourceWorkSheet $ws ` + -PivotRows Status -PivotData Name } | Should -Not -Throw + $excel.Workbook.Worksheets["pt5"] | Should -Not -BeNullOrEmpty + Close-ExcelPackage -NoSave $excel + } + it "Accepts Table, Table.Addres " { + $excel = Get-Service | Export-Excel -Path $path -WorksheetName Services -PassThru -AutoSize -DisplayPropertySet -TableName servicetable -Title "Services on $Env:COMPUTERNAME" + $ws = $excel.Workbook.Worksheets["Services"] #can get a worksheet by name or index - starting at 1 + #Can get a table by name or -stating at zero. Can specify the range for a pivot as or Table or TableAddress + { Add-PivotTable -ExcelPackage $excel -PivotTableName pt1 -SourceRange $ws.tables["servicetable"]` + -PivotRows Status -PivotData Name } | Should -Not -Throw + $excel.Workbook.Worksheets["pt1"] | Should -Not -BeNullOrEmpty + { Add-PivotTable -ExcelPackage $excel -PivotTableName pt2 -SourceRange $ws.tables[0].Address ` + -PivotRows Status -PivotData Name } | Should -Not -Throw + $excel.Workbook.Worksheets["pt2"] | Should -Not -BeNullOrEmpty + Close-ExcelPackage -NoSave $excel + } + } } \ No newline at end of file From 6a956dbd7e6809edb2abdd1bdc8aa468e25eb2c5 Mon Sep 17 00:00:00 2001 From: dfinke Date: Mon, 11 Apr 2022 16:58:13 -0400 Subject: [PATCH 097/140] delete xlsx after tests run --- __tests__/ImportExcelHeaderName.tests.ps1 | 4 ++++ __tests__/testImportExcelSparse.xlsx | Bin 2666 -> 0 bytes 2 files changed, 4 insertions(+) delete mode 100644 __tests__/testImportExcelSparse.xlsx diff --git a/__tests__/ImportExcelHeaderName.tests.ps1 b/__tests__/ImportExcelHeaderName.tests.ps1 index 41944df..391bbd1 100644 --- a/__tests__/ImportExcelHeaderName.tests.ps1 +++ b/__tests__/ImportExcelHeaderName.tests.ps1 @@ -63,6 +63,10 @@ Describe "Import-Excel on a sheet with no headings" { } } + AfterAll { + Remove-Item $PSScriptRoot\testImportExcelSparse.xlsx -ErrorAction SilentlyContinue + } + It "Import-Excel should have this shape" { $actual = @(Import-Excel $xlfile) diff --git a/__tests__/testImportExcelSparse.xlsx b/__tests__/testImportExcelSparse.xlsx deleted file mode 100644 index 099cbf7a8c72f059fdd9559be3fc81252573df38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2666 zcmZ{m2|UyPAIHaBF>)nWQ=^oHO=EIP2j-Z$T9Ti!kYnYxB1c&WIVVMObj*=6$FF1= zk@a&%;V0%+Q3<)~x9R`*8~^|B{e3+4dF=7n`}5fQ`Fg$I?=Kn!r96HpS znBveWYy=y|HQ31}(R|@fa$*?k^T4WHH;W+Cq}fhjYX(fbAnrYo>^by^izpyt)7L#6 z-vx*9WPcgnCozBd(;t&H*!a1q0O;QRZt54Qm?ksCP7)*`wb60i*+-7PgFYs3{Jeh^ ziFjvf29fg!p`b%fZ0#L>0m1cQ;}6Vasmdo~PQrTR%Y(}8rm4~J@7!wo5vnCK!#$_y z151+C1#UF_Gp5zEjjG#4m66F zj~yR+3)qbQk8veTpo&bm0?gCN7w_e#s>1q=Z>I`H!azL3_E;i0g4YEU6$c-=@P%W- zj)$Wce}|timw?j=_F7q5?Jhqz5u@8liYN+)v_;&v&FA&x8tiYI zk8MbkNwdG`3Y9w@B*XO`UMDtbxS-i~E6M1N#-3$tGlJNdWs`?!Sqcdo{@EQ~+$ycy zfUE=bmI(bSd;F2-x*H}@%6rY~YnpNScb>d(JVW){XqG!&l>eF1@&t88kX0soFt_CX#6b?s}>A8f3%5lMX|p~rtNDww_) z`V-96rvV&Vk|N(|dYINdcbGmlsM1({aj&{|?1lG(>i`xL_R6<1iNGc2_A*%@H~|3Z z-%Nh1&rW8;3B^h6EIcHqrm1?(=|65-Rg>XURae0V?@VPg-!*sjkAL>mu)`d5A!T24 z{l2bOG``{~+Y_U<1ebKDNQ-mJILc`ON$an=p$8>ELL|wShU1`*Z+%ffQ>^m`MZ4=F z@4|PR5YALAARzW|tAncEba_(`zlUP|@`3rg1J-lr?{ZX|RbArw)~uehXr243)Ma2X zeJF2T_E1X}UueQ|OSUn;xZf$?`@gQpCb zsF1Q9=&xR=txWV63b5#~GuTQ;ul!`9KGQAQ%!wnp=@>tEJl@|=b>o0JJK`%T02@l_hV_{tCaW9 z$5{WIN&_kDt0PvNYK>=GT+AG-2X#BlMHe1f)N#RR49pW-Gn7lFx{DU{{sb{X&{*3( zhf-VS7~pzZ91G#Hy37gL*oI_!p1Da(v0i}O_eoB|9mK;$&rtA$35 z$*@FVN4-@98@I+KN2Ul2rbPvRi{R%U;)VBPk-v^XF7&q=&&P?_7SGnq zpmaF@yi8lAT!aY_We;+XEx%3+2EZ(_6a5jU42^#Dcu>aE^cCMc?@71X`je5AV`v^j z=Ma4wPvwq+PQaPylF|IW*c(%;PzUL`zcKp~M)nN7w{4)IrKeE4-K3&RE2-|vr~}CF zG)cJJ$@gf7SCgR1Do=$Tt?5o$@0Y^21`fverhUWx0(Dw#*Q8F2c%!cH-Nua%+&l}g z|K-?vCs1s4KB>ITtvGCBbgR786kv+DmZB zB2bd?n4Z)Q&c0{yrvogv<;a7VVV{Y9L7TSGG3h!jc$bOcdX{Fs; zkya)8SGll<#UfEsNW;YyX6;b~_Gv&Q%*8i5&2qyv1xLFcAl=k8FN^5=wj~zy9(2&g z#fI)ks4)lgg&+@j9r4a1w-p@yHNR99gI=-5t@6G^vaHEoC>q7Vsmv_*-`+`>9N6Oj zyrFErfPG!DcJF3jnOxa6@%BXanaZKCzi&@v*M?=n%}C_^ox0tUXcRXO>sP$Y M=Oq(yG9T;PKU+CKg#Z8m From f83f654c4a2641e8295623e8e5bd8191323469bb Mon Sep 17 00:00:00 2001 From: dfinke Date: Mon, 11 Apr 2022 16:58:55 -0400 Subject: [PATCH 098/140] Update how Import-Excel reads sheets, and remain backward compatible --- Public/Import-Excel.ps1 | 173 +++++++++--------- .../ImportExcelReadSheets.tests.ps1 | 47 +++++ __tests__/ImportExcelTests/yearlySales.xlsx | Bin 0 -> 54899 bytes 3 files changed, 135 insertions(+), 85 deletions(-) create mode 100644 __tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 create mode 100644 __tests__/ImportExcelTests/yearlySales.xlsx diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index adadc82..630b907 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -15,7 +15,7 @@ [Alias('Sheet')] [Parameter(Position = 1)] [ValidateNotNullOrEmpty()] - [String]$WorksheetName, + [String[]]$WorksheetName, [Parameter(ParameterSetName = 'PathB' , Mandatory)] [Parameter(ParameterSetName = 'PackageB', Mandatory)] [String[]]$HeaderName , @@ -64,7 +64,7 @@ try { if ($ImportColumns) { - $end = $Worksheet.Dimension.End.Column + $end = $sheet.Dimension.End.Column # Check $ImportColumns if ($ImportColumns[0] -le 0) { throw "The first entry in ImportColumns must be equal or greater 1" ; return } # Check $StartColumn and $EndColumn @@ -95,7 +95,7 @@ foreach ($C in $Columns) { #allow "False" or "0" to be column headings - $Worksheet.Cells[$StartRow, $C] | Where-Object { -not [string]::IsNullOrEmpty($_.Value) } | Select-Object @{N = 'Column'; E = { $C } }, Value + $sheet.Cells[$StartRow, $C] | Where-Object { -not [string]::IsNullOrEmpty($_.Value) } | Select-Object @{N = 'Column'; E = { $C } }, Value } } } @@ -125,103 +125,106 @@ } try { #Select worksheet - if (-not $WorksheetName) { $Worksheet = $ExcelPackage.Workbook.Worksheets[1] } + if ($WorksheetName -eq '*') { $Worksheet = $ExcelPackage.Workbook.Worksheets } + elseif (-not $WorksheetName) { $Worksheet = $ExcelPackage.Workbook.Worksheets[1] } elseif (-not ($Worksheet = $ExcelPackage.Workbook.Worksheets[$WorksheetName])) { throw "Worksheet '$WorksheetName' not found, the workbook only contains the worksheets '$($ExcelPackage.Workbook.Worksheets)'. If you only wish to select the first worksheet, please remove the '-WorksheetName' parameter." ; return } - #region Get rows and columns - #If we are doing dataonly it is quicker to work out which rows to ignore before processing the cells. - if (-not $EndRow ) { $EndRow = $Worksheet.Dimension.End.Row } - if (-not $EndColumn) { $EndColumn = $Worksheet.Dimension.End.Column } - $endAddress = [OfficeOpenXml.ExcelAddress]::TranslateFromR1C1("R[$EndRow]C[$EndColumn]", 0, 0) - if ($DataOnly) { - #If we are using headers startrow will be the header-row so examine data from startRow + 1, - if ($NoHeader) { $range = "A" + ($StartRow ) + ":" + $endAddress } - else { $range = "A" + ($StartRow + 1 ) + ":" + $endAddress } - #We're going to look at every cell and build 2 hash tables holding rows & columns which contain data. - #Want to Avoid 'select unique' operations & large Sorts, becuse time time taken increases with square - #of number of items (PS uses heapsort at large size). Instead keep a list of what we have seen, - #using Hash tables: "we've seen it" is all we need, no need to worry about "seen it before" / "Seen it many times". - $colHash = @{ } - $rowHash = @{ } - foreach ($cell in $Worksheet.Cells[$range]) { - if ($null -ne $cell.Value ) { $colHash[$cell.Start.Column] = 1; $rowHash[$cell.Start.row] = 1 } - } - $rows = ( $StartRow..$EndRow ).Where( { $rowHash[$_] }) - $columns = ($StartColumn..$EndColumn).Where( { $colHash[$_] }) - } - else { - $Columns = $StartColumn .. $EndColumn ; if ($StartColumn -gt $EndColumn) { Write-Warning -Message "Selecting columns $StartColumn to $EndColumn might give odd results." } - if ($NoHeader) { $rows = $StartRow..$EndRow ; if ($StartRow -gt $EndRow) { Write-Warning -Message "Selecting rows $StartRow to $EndRow might give odd results." } } - elseif ($HeaderName) { $rows = $StartRow..$EndRow } - else { - $rows = (1 + $StartRow)..$EndRow - if ($StartRow -eq 1 -and $EndRow -eq 1) { - $rows = 0 + foreach ($sheet in $Worksheet) { + #region Get rows and columns + #If we are doing dataonly it is quicker to work out which rows to ignore before processing the cells. + if (-not $EndRow ) { $EndRow = $sheet.Dimension.End.Row } + if (-not $EndColumn) { $EndColumn = $sheet.Dimension.End.Column } + $endAddress = [OfficeOpenXml.ExcelAddress]::TranslateFromR1C1("R[$EndRow]C[$EndColumn]", 0, 0) + if ($DataOnly) { + #If we are using headers startrow will be the header-row so examine data from startRow + 1, + if ($NoHeader) { $range = "A" + ($StartRow ) + ":" + $endAddress } + else { $range = "A" + ($StartRow + 1 ) + ":" + $endAddress } + #We're going to look at every cell and build 2 hash tables holding rows & columns which contain data. + #Want to Avoid 'select unique' operations & large Sorts, becuse time time taken increases with square + #of number of items (PS uses heapsort at large size). Instead keep a list of what we have seen, + #using Hash tables: "we've seen it" is all we need, no need to worry about "seen it before" / "Seen it many times". + $colHash = @{ } + $rowHash = @{ } + foreach ($cell in $sheet.Cells[$range]) { + if ($null -ne $cell.Value ) { $colHash[$cell.Start.Column] = 1; $rowHash[$cell.Start.row] = 1 } } + $rows = ( $StartRow..$EndRow ).Where( { $rowHash[$_] }) + $columns = ($StartColumn..$EndColumn).Where( { $colHash[$_] }) } + else { + $Columns = $StartColumn .. $EndColumn ; if ($StartColumn -gt $EndColumn) { Write-Warning -Message "Selecting columns $StartColumn to $EndColumn might give odd results." } + if ($NoHeader) { $rows = $StartRow..$EndRow ; if ($StartRow -gt $EndRow) { Write-Warning -Message "Selecting rows $StartRow to $EndRow might give odd results." } } + elseif ($HeaderName) { $rows = $StartRow..$EndRow } + else { + $rows = (1 + $StartRow)..$EndRow + if ($StartRow -eq 1 -and $EndRow -eq 1) { + $rows = 0 + } + } - # ; if ($StartRow -ge $EndRow) { Write-Warning -Message "Selecting $StartRow as the header with data in $(1+$StartRow) to $EndRow might give odd results." } } - } - #endregion - #region Create property names - if ((-not $Columns) -or (-not ($PropertyNames = Get-PropertyNames -Columns $Columns -StartRow $StartRow))) { - throw "No column headers found on top row '$StartRow'. If column headers in the worksheet are not a requirement then please use the '-NoHeader' or '-HeaderName' parameter."; return - } - if ($Duplicates = $PropertyNames | Group-Object Value | Where-Object Count -GE 2) { - throw "Duplicate column headers found on row '$StartRow' in columns '$($Duplicates.Group.Column)'. Column headers must be unique, if this is not a requirement please use the '-NoHeader' or '-HeaderName' parameter."; return - } - #endregion - if (-not $rows) { - Write-Warning "Worksheet '$WorksheetName' in workbook '$Path' contains no data in the rows after top row '$StartRow'" - } - else { - #region Create one object per row - if ($AsText -or $AsDate) { - <#join items in AsText together with ~~~ . Escape any regex special characters... + # ; if ($StartRow -ge $EndRow) { Write-Warning -Message "Selecting $StartRow as the header with data in $(1+$StartRow) to $EndRow might give odd results." } } + } + #endregion + #region Create property names + if ((-not $Columns) -or (-not ($PropertyNames = Get-PropertyNames -Columns $Columns -StartRow $StartRow))) { + throw "No column headers found on top row '$StartRow'. If column headers in the worksheet are not a requirement then please use the '-NoHeader' or '-HeaderName' parameter."; return + } + if ($Duplicates = $PropertyNames | Group-Object Value | Where-Object Count -GE 2) { + throw "Duplicate column headers found on row '$StartRow' in columns '$($Duplicates.Group.Column)'. Column headers must be unique, if this is not a requirement please use the '-NoHeader' or '-HeaderName' parameter."; return + } + #endregion + if (-not $rows) { + Write-Warning "Worksheet '$WorksheetName' in workbook '$Path' contains no data in the rows after top row '$StartRow'" + } + else { + #region Create one object per row + if ($AsText -or $AsDate) { + <#join items in AsText together with ~~~ . Escape any regex special characters... # which turns "*" into "\*" make it ".*". Convert ~~~ to $|^ and top and tail with ^%; So if we get "Week", "[Time]" and "*date*" ; make the expression ^week$|^\[Time\]$|^.*Date.*$ $make a regex for this which is case insensitive (option 1) and compiled (option 8) #> - $TextColExpression = '' - if ($AsText) { - $TextColExpression += '(?^' + [regex]::Escape($AsText -join '~~~').replace('\*', '.*').replace('~~~', '$|^') + '$)' - } - if ($AsText -and $AsDate) { - $TextColExpression += "|" - } - if ($AsDate) { - $TextColExpression += '(?^' + [regex]::Escape($AsDate -join '~~~').replace('\*', '.*').replace('~~~', '$|^') + '$)' - } - $TextColRegEx = New-Object -TypeName regex -ArgumentList $TextColExpression , 9 - } - else { $TextColRegEx = $null } - foreach ($R in $rows) { - #Disabled write-verbose for speed - # Write-Verbose "Import row '$R'" - $NewRow = [Ordered]@{ } - if ($TextColRegEx) { - foreach ($P in $PropertyNames) { - $MatchTest = $TextColRegEx.Match($P.value) - if ($MatchTest.groups.name -eq "astext") { - $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Text - } - elseif ($MatchTest.groups.name -eq "asdate" -and $Worksheet.Cells[$R, $P.Column].Value -is [System.ValueType]) { - $NewRow[$P.Value] = [datetime]::FromOADate(($Worksheet.Cells[$R, $P.Column].Value)) - } - else { $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value } + $TextColExpression = '' + if ($AsText) { + $TextColExpression += '(?^' + [regex]::Escape($AsText -join '~~~').replace('\*', '.*').replace('~~~', '$|^') + '$)' } - } - else { - foreach ($P in $PropertyNames) { - $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value - # Write-Verbose "Import cell '$($Worksheet.Cells[$R, $P.Column].Address)' with property name '$($p.Value)' and value '$($Worksheet.Cells[$R, $P.Column].Value)'." + if ($AsText -and $AsDate) { + $TextColExpression += "|" } + if ($AsDate) { + $TextColExpression += '(?^' + [regex]::Escape($AsDate -join '~~~').replace('\*', '.*').replace('~~~', '$|^') + '$)' + } + $TextColRegEx = New-Object -TypeName regex -ArgumentList $TextColExpression , 9 } - [PSCustomObject]$NewRow + else { $TextColRegEx = $null } + foreach ($R in $rows) { + #Disabled write-verbose for speed + # Write-Verbose "Import row '$R'" + $NewRow = [Ordered]@{ } + if ($TextColRegEx) { + foreach ($P in $PropertyNames) { + $MatchTest = $TextColRegEx.Match($P.value) + if ($MatchTest.groups.name -eq "astext") { + $NewRow[$P.Value] = $sheet.Cells[$R, $P.Column].Text + } + elseif ($MatchTest.groups.name -eq "asdate" -and $sheet.Cells[$R, $P.Column].Value -is [System.ValueType]) { + $NewRow[$P.Value] = [datetime]::FromOADate(($sheet.Cells[$R, $P.Column].Value)) + } + else { $NewRow[$P.Value] = $sheet.Cells[$R, $P.Column].Value } + } + } + else { + foreach ($P in $PropertyNames) { + $NewRow[$P.Value] = $sheet.Cells[$R, $P.Column].Value + # Write-Verbose "Import cell '$($Worksheet.Cells[$R, $P.Column].Address)' with property name '$($p.Value)' and value '$($Worksheet.Cells[$R, $P.Column].Value)'." + } + } + [PSCustomObject]$NewRow + } + #endregion } - #endregion } } catch { throw "Failed importing the Excel workbook '$Path' with worksheet '$WorksheetName': $_"; return } diff --git a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 new file mode 100644 index 0000000..c8b2185 --- /dev/null +++ b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 @@ -0,0 +1,47 @@ +Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force + +Describe 'Different ways to import sheets' -Tag ImportExcelReadSheets { + BeforeAll { + $xlFilename = "$PSScriptRoot\yearlySales.xlsx" + } + + Context 'Test reading sheets' { + It 'Should read one sheet' { + $actual = Import-Excel $xlFilename + + $actual.Count | Should -Be 100 + $actual[0].Month | Should -BeExactly "April" + } + + It 'Should read two sheets' { + $actual = Import-Excel $xlFilename march, june + + $actual.Count | Should -Be 200 + $actual[0].Month | Should -BeExactly "March" + $actual[100].Month | Should -BeExactly "June" + } + + It 'Should read all the sheets' { + $actual = Import-Excel $xlFilename * + + $actual.Count | Should -Be 1200 + + $actual[0].Month | Should -BeExactly "April" + $actual[100].Month | Should -BeExactly "August" + $actual[200].Month | Should -BeExactly "December" + $actual[300].Month | Should -BeExactly "February" + $actual[400].Month | Should -BeExactly "January" + $actual[500].Month | Should -BeExactly "July" + $actual[600].Month | Should -BeExactly "June" + $actual[700].Month | Should -BeExactly "March" + $actual[800].Month | Should -BeExactly "May" + $actual[900].Month | Should -BeExactly "November" + $actual[1000].Month | Should -BeExactly "October" + $actual[1100].Month | Should -BeExactly "September" + } + + It 'Should throw if it cannot find the sheet' { + { Import-Excel $xlFilename april, june, notthere } | Should -Throw + } + } +} \ No newline at end of file diff --git a/__tests__/ImportExcelTests/yearlySales.xlsx b/__tests__/ImportExcelTests/yearlySales.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d30993a1d57932fef39a8e6be132d9e49914247c GIT binary patch literal 54899 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 a|Fb&dsWLtR=2sNJryCCo3p$AT@BaWQ9!4Di literal 0 HcmV?d00001 From d55f0e64d4228179338ba179ad1b357565111806 Mon Sep 17 00:00:00 2001 From: dfinke Date: Mon, 11 Apr 2022 18:48:17 -0400 Subject: [PATCH 099/140] WIP - Add sheets and contents to a hashtable --- Public/Import-Excel.ps1 | 12 +++++- .../ImportExcelReadSheets.tests.ps1 | 39 +++++++++++-------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index 630b907..bd9cb8c 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -131,7 +131,10 @@ throw "Worksheet '$WorksheetName' not found, the workbook only contains the worksheets '$($ExcelPackage.Workbook.Worksheets)'. If you only wish to select the first worksheet, please remove the '-WorksheetName' parameter." ; return } + $xlBook = [Ordered]@{} foreach ($sheet in $Worksheet) { + $targetSheetname = $sheet.Name + $xlBook["$targetSheetname"] = @() #region Get rows and columns #If we are doing dataonly it is quicker to work out which rows to ignore before processing the cells. if (-not $EndRow ) { $EndRow = $sheet.Dimension.End.Row } @@ -221,7 +224,7 @@ # Write-Verbose "Import cell '$($Worksheet.Cells[$R, $P.Column].Address)' with property name '$($p.Value)' and value '$($Worksheet.Cells[$R, $P.Column].Value)'." } } - [PSCustomObject]$NewRow + $xlBook["$targetSheetname"] += [PSCustomObject]$NewRow } #endregion } @@ -230,6 +233,13 @@ catch { throw "Failed importing the Excel workbook '$Path' with worksheet '$WorksheetName': $_"; return } finally { if ($Path) { $stream.close(); $ExcelPackage.Dispose() } + + if ($Worksheet.Count -eq 1) { + $xlBook["$targetSheetname"] + } + else { + $xlBook + } } } } diff --git a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 index c8b2185..a2abc40 100644 --- a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 +++ b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 @@ -1,3 +1,7 @@ +#Requires -Modules Pester +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments','',Justification='False Positives')] +param() + Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force Describe 'Different ways to import sheets' -Tag ImportExcelReadSheets { @@ -11,33 +15,34 @@ Describe 'Different ways to import sheets' -Tag ImportExcelReadSheets { $actual.Count | Should -Be 100 $actual[0].Month | Should -BeExactly "April" + $actual[99].Month | Should -BeExactly "April" } It 'Should read two sheets' { $actual = Import-Excel $xlFilename march, june - $actual.Count | Should -Be 200 - $actual[0].Month | Should -BeExactly "March" - $actual[100].Month | Should -BeExactly "June" + $actual.keys.Count | Should -Be 2 + $actual["March"].Count | Should -Be 100 + $actual["June"].Count | Should -Be 100 } It 'Should read all the sheets' { $actual = Import-Excel $xlFilename * - $actual.Count | Should -Be 1200 - - $actual[0].Month | Should -BeExactly "April" - $actual[100].Month | Should -BeExactly "August" - $actual[200].Month | Should -BeExactly "December" - $actual[300].Month | Should -BeExactly "February" - $actual[400].Month | Should -BeExactly "January" - $actual[500].Month | Should -BeExactly "July" - $actual[600].Month | Should -BeExactly "June" - $actual[700].Month | Should -BeExactly "March" - $actual[800].Month | Should -BeExactly "May" - $actual[900].Month | Should -BeExactly "November" - $actual[1000].Month | Should -BeExactly "October" - $actual[1100].Month | Should -BeExactly "September" + $actual.keys.Count | Should -Be 12 + + $actual["January"].Count | Should -Be 100 + $actual["February"].Count | Should -Be 100 + $actual["March"].Count | Should -Be 100 + $actual["April"].Count | Should -Be 100 + $actual["May"].Count | Should -Be 100 + $actual["June"].Count | Should -Be 100 + $actual["July"].Count | Should -Be 100 + $actual["August"].Count | Should -Be 100 + $actual["September"].Count | Should -Be 100 + $actual["October"].Count | Should -Be 100 + $actual["November"].Count | Should -Be 100 + $actual["December"].Count | Should -Be 100 } It 'Should throw if it cannot find the sheet' { From 483f761016155333bb667a659226458d3716c86b Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 12 Apr 2022 18:03:34 -0400 Subject: [PATCH 100/140] Add switch to not return data as a dictionary --- Public/Import-Excel.ps1 | 10 ++++++++-- .../ImportExcelReadSheets.tests.ps1 | 13 ++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index bd9cb8c..002579a 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -36,7 +36,8 @@ [string[]]$AsDate, [ValidateNotNullOrEmpty()] [String]$Password, - [Int[]]$ImportColumns + [Int[]]$ImportColumns, + [Switch]$NoHashtable ) end { $sw = [System.Diagnostics.Stopwatch]::StartNew() @@ -234,7 +235,12 @@ finally { if ($Path) { $stream.close(); $ExcelPackage.Dispose() } - if ($Worksheet.Count -eq 1) { + if ($NoHashtable) { + foreach ($entry in $xlbook.GetEnumerator()) { + $entry.Value + } + } + elseif ($Worksheet.Count -eq 1) { $xlBook["$targetSheetname"] } else { diff --git a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 index a2abc40..d1e4e3d 100644 --- a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 +++ b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 @@ -1,5 +1,5 @@ #Requires -Modules Pester -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments','',Justification='False Positives')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'False Positives')] param() Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force @@ -48,5 +48,16 @@ Describe 'Different ways to import sheets' -Tag ImportExcelReadSheets { It 'Should throw if it cannot find the sheet' { { Import-Excel $xlFilename april, june, notthere } | Should -Throw } + + It 'Should return an array not a dictionary' { + $actual = Import-Excel $xlFilename april, june -NoHashtable + + $actual.Count | Should -Be 200 + $group = $actual | Group-Object month -NoElement + + $group.Count | Should -Be 2 + $group[0].Name | Should -BeExactly 'April' + $group[1].Name | Should -BeExactly 'June' + } } } \ No newline at end of file From 7f36b44fa8a533eb93de3882b034db05ce13e64d Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 12 Apr 2022 18:08:11 -0400 Subject: [PATCH 101/140] renamed to NotAsDictionary --- Public/Import-Excel.ps1 | 4 ++-- __tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index 002579a..92fc24c 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -37,7 +37,7 @@ [ValidateNotNullOrEmpty()] [String]$Password, [Int[]]$ImportColumns, - [Switch]$NoHashtable + [Switch]$NotAsDictionary ) end { $sw = [System.Diagnostics.Stopwatch]::StartNew() @@ -235,7 +235,7 @@ finally { if ($Path) { $stream.close(); $ExcelPackage.Dispose() } - if ($NoHashtable) { + if ($NotAsDictionary) { foreach ($entry in $xlbook.GetEnumerator()) { $entry.Value } diff --git a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 index d1e4e3d..92d1589 100644 --- a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 +++ b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 @@ -50,7 +50,7 @@ Describe 'Different ways to import sheets' -Tag ImportExcelReadSheets { } It 'Should return an array not a dictionary' { - $actual = Import-Excel $xlFilename april, june -NoHashtable + $actual = Import-Excel $xlFilename april, june -NotAsDictionary $actual.Count | Should -Be 200 $group = $actual | Group-Object month -NoElement From b997e90e78e50f1709636b76cc6bdd0482d377d7 Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 19 Apr 2022 09:23:36 -0400 Subject: [PATCH 102/140] bump version --- ImportExcel.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index 7d7a2be..c6c22be 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.4.1' + ModuleVersion = '7.4.2' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' From 91b0e8b0ed629c1624d01bf866aaf5e278238572 Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 19 Apr 2022 09:26:20 -0400 Subject: [PATCH 103/140] update https://github.com/dfinke/ImportExcel/pull/1145 --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index 5f26638..c27429a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,7 @@ +# v7.4.2 + +- Thank you [James Mueller](https://github.com/jamesmmueller) Updated `ConvertFrom-ExcelToSQLInsert` to handle single quotes in the SQL statement. + - Thank you to Josh Hendricks - Add images to spreadsheets. [Check it out](https://github.com/dfinke/ImportExcel/tree/master/Examples/AddImage) - Catch up with him on [GitHub](https://github.com/joshooaj) and [Twitter](https://twitter.com/joshooaj) for the idea From b0024cf2c48b30ab61ab7dc08315bd3465ecf347 Mon Sep 17 00:00:00 2001 From: dfinke Date: Thu, 28 Apr 2022 19:44:40 -0400 Subject: [PATCH 104/140] bump version --- ImportExcel.psd1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index c6c22be..1db1af9 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.4.2' + ModuleVersion = '7.4.3' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' @@ -48,11 +48,13 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5 'ConvertTo-ExcelXlsx', 'Copy-ExcelWorksheet', 'DoChart', + 'Enable-ExcelAutoFilter', 'Expand-NumberFormat', 'Export-Excel', 'Export-ExcelSheet', 'Get-ExcelColumnName', - 'Get-ExcelFileSummary', + 'Get-ExcelFileSummary', + 'Get-ExcelSheetDimensionAddress', 'Get-ExcelSheetInfo', 'Get-ExcelWorkbookInfo', 'Get-HtmlTable', @@ -63,8 +65,9 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5 'Import-UPS', 'Import-USPS', 'Invoke-AllTests', - 'Invoke-Sum', + 'Enable-ExcelAutofit', 'Invoke-ExcelQuery', + 'Invoke-Sum', 'Join-Worksheet', 'LineChart', 'Merge-MultipleSheets', From eb103647221af632827d8d7d4bddea39f7571e94 Mon Sep 17 00:00:00 2001 From: dfinke Date: Thu, 28 Apr 2022 19:44:49 -0400 Subject: [PATCH 105/140] Add helpers --- Public/Enable-ExcelAutoFilter.ps1 | 16 ++++++++++++++++ Public/Enable-ExcelAutofit.ps1 | 16 ++++++++++++++++ Public/Get-ExcelSheetDimensionAddress.ps1 | 15 +++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 Public/Enable-ExcelAutoFilter.ps1 create mode 100644 Public/Enable-ExcelAutofit.ps1 create mode 100644 Public/Get-ExcelSheetDimensionAddress.ps1 diff --git a/Public/Enable-ExcelAutoFilter.ps1 b/Public/Enable-ExcelAutoFilter.ps1 new file mode 100644 index 0000000..0c4a3d5 --- /dev/null +++ b/Public/Enable-ExcelAutoFilter.ps1 @@ -0,0 +1,16 @@ +function Enable-ExcelAutoFilter { + <# + .SYNOPSIS + Enable the Excel AutoFilter + + .EXAMPLE + Enable-ExcelAutoFilter $targetSheet + #> + param( + [Parameter(Mandatory)] + [OfficeOpenXml.ExcelWorksheet]$Worksheet + ) + + $range = Get-ExcelSheetDimensionAddress $Worksheet + $Worksheet.Cells[$range].AutoFilter = $true +} \ No newline at end of file diff --git a/Public/Enable-ExcelAutofit.ps1 b/Public/Enable-ExcelAutofit.ps1 new file mode 100644 index 0000000..0d117d4 --- /dev/null +++ b/Public/Enable-ExcelAutofit.ps1 @@ -0,0 +1,16 @@ +function Enable-ExcelAutofit { + <# + .SYNOPSIS + Make all text fit the cells + + .EXAMPLE + Enable-ExcelAutofit $excel.Sheet1 + #> + param( + [Parameter(Mandatory)] + [OfficeOpenXml.ExcelWorksheet]$Worksheet + ) + + $range = Get-ExcelSheetDimensionAddress $Worksheet + $Worksheet.Cells[$range].AutoFitColumns() +} \ No newline at end of file diff --git a/Public/Get-ExcelSheetDimensionAddress.ps1 b/Public/Get-ExcelSheetDimensionAddress.ps1 new file mode 100644 index 0000000..993b7f9 --- /dev/null +++ b/Public/Get-ExcelSheetDimensionAddress.ps1 @@ -0,0 +1,15 @@ +function Get-ExcelSheetDimensionAddress { + <# + .SYNOPSIS + Get the Excel address of the dimension of a sheet + + .EXAMPLE + Get-ExcelSheetDimensionAddress $excel.Sheet1 + #> + param( + [Parameter(Mandatory)] + [OfficeOpenXml.ExcelWorksheet]$Worksheet + ) + + $Worksheet.Dimension.Address +} From a10ade898aa22f7e52d8f0519e034bcba249ff8d Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 29 Apr 2022 20:39:15 -0400 Subject: [PATCH 106/140] Remove xl file after use in test --- __tests__/ImportExcelHeaderName.tests.ps1 | 1 + __tests__/testImportExcelSparse.xlsx | Bin 2666 -> 0 bytes 2 files changed, 1 insertion(+) delete mode 100644 __tests__/testImportExcelSparse.xlsx diff --git a/__tests__/ImportExcelHeaderName.tests.ps1 b/__tests__/ImportExcelHeaderName.tests.ps1 index 41944df..90ef05e 100644 --- a/__tests__/ImportExcelHeaderName.tests.ps1 +++ b/__tests__/ImportExcelHeaderName.tests.ps1 @@ -230,6 +230,7 @@ Describe "Import-Excel on a sheet with no headings" { $actual.Count | Should -Be 1 + Remove-Item $xlfile # Looks like -DataOnly does not handle empty columns # $actual[0].FirstName | Should -BeExactly 'Jean-Claude' # $actual[0].SecondName | Should -BeExactly 'Vandamme' diff --git a/__tests__/testImportExcelSparse.xlsx b/__tests__/testImportExcelSparse.xlsx deleted file mode 100644 index 099cbf7a8c72f059fdd9559be3fc81252573df38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2666 zcmZ{m2|UyPAIHaBF>)nWQ=^oHO=EIP2j-Z$T9Ti!kYnYxB1c&WIVVMObj*=6$FF1= zk@a&%;V0%+Q3<)~x9R`*8~^|B{e3+4dF=7n`}5fQ`Fg$I?=Kn!r96HpS znBveWYy=y|HQ31}(R|@fa$*?k^T4WHH;W+Cq}fhjYX(fbAnrYo>^by^izpyt)7L#6 z-vx*9WPcgnCozBd(;t&H*!a1q0O;QRZt54Qm?ksCP7)*`wb60i*+-7PgFYs3{Jeh^ ziFjvf29fg!p`b%fZ0#L>0m1cQ;}6Vasmdo~PQrTR%Y(}8rm4~J@7!wo5vnCK!#$_y z151+C1#UF_Gp5zEjjG#4m66F zj~yR+3)qbQk8veTpo&bm0?gCN7w_e#s>1q=Z>I`H!azL3_E;i0g4YEU6$c-=@P%W- zj)$Wce}|timw?j=_F7q5?Jhqz5u@8liYN+)v_;&v&FA&x8tiYI zk8MbkNwdG`3Y9w@B*XO`UMDtbxS-i~E6M1N#-3$tGlJNdWs`?!Sqcdo{@EQ~+$ycy zfUE=bmI(bSd;F2-x*H}@%6rY~YnpNScb>d(JVW){XqG!&l>eF1@&t88kX0soFt_CX#6b?s}>A8f3%5lMX|p~rtNDww_) z`V-96rvV&Vk|N(|dYINdcbGmlsM1({aj&{|?1lG(>i`xL_R6<1iNGc2_A*%@H~|3Z z-%Nh1&rW8;3B^h6EIcHqrm1?(=|65-Rg>XURae0V?@VPg-!*sjkAL>mu)`d5A!T24 z{l2bOG``{~+Y_U<1ebKDNQ-mJILc`ON$an=p$8>ELL|wShU1`*Z+%ffQ>^m`MZ4=F z@4|PR5YALAARzW|tAncEba_(`zlUP|@`3rg1J-lr?{ZX|RbArw)~uehXr243)Ma2X zeJF2T_E1X}UueQ|OSUn;xZf$?`@gQpCb zsF1Q9=&xR=txWV63b5#~GuTQ;ul!`9KGQAQ%!wnp=@>tEJl@|=b>o0JJK`%T02@l_hV_{tCaW9 z$5{WIN&_kDt0PvNYK>=GT+AG-2X#BlMHe1f)N#RR49pW-Gn7lFx{DU{{sb{X&{*3( zhf-VS7~pzZ91G#Hy37gL*oI_!p1Da(v0i}O_eoB|9mK;$&rtA$35 z$*@FVN4-@98@I+KN2Ul2rbPvRi{R%U;)VBPk-v^XF7&q=&&P?_7SGnq zpmaF@yi8lAT!aY_We;+XEx%3+2EZ(_6a5jU42^#Dcu>aE^cCMc?@71X`je5AV`v^j z=Ma4wPvwq+PQaPylF|IW*c(%;PzUL`zcKp~M)nN7w{4)IrKeE4-K3&RE2-|vr~}CF zG)cJJ$@gf7SCgR1Do=$Tt?5o$@0Y^21`fverhUWx0(Dw#*Q8F2c%!cH-Nua%+&l}g z|K-?vCs1s4KB>ITtvGCBbgR786kv+DmZB zB2bd?n4Z)Q&c0{yrvogv<;a7VVV{Y9L7TSGG3h!jc$bOcdX{Fs; zkya)8SGll<#UfEsNW;YyX6;b~_Gv&Q%*8i5&2qyv1xLFcAl=k8FN^5=wj~zy9(2&g z#fI)ks4)lgg&+@j9r4a1w-p@yHNR99gI=-5t@6G^vaHEoC>q7Vsmv_*-`+`>9N6Oj zyrFErfPG!DcJF3jnOxa6@%BXanaZKCzi&@v*M?=n%}C_^ox0tUXcRXO>sP$Y M=Oq(yG9T;PKU+CKg#Z8m From b634bf9d93bd6e4644ebc42e85e2f407c7bf6551 Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 29 Apr 2022 20:39:51 -0400 Subject: [PATCH 107/140] Fix fir #1172 --- Public/Import-Excel.ps1 | 2 + .../ReadMultipleXLSXFiles.tests.ps1 | 57 ++++++++++++++++++ __tests__/ImportExcelTests/rows05.xlsx | Bin 0 -> 2783 bytes __tests__/ImportExcelTests/rows10.xlsx | Bin 0 -> 2948 bytes 4 files changed, 59 insertions(+) create mode 100644 __tests__/ImportExcelTests/ReadMultipleXLSXFiles.tests.ps1 create mode 100644 __tests__/ImportExcelTests/rows05.xlsx create mode 100644 __tests__/ImportExcelTests/rows10.xlsx diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index adadc82..49982cb 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -226,6 +226,8 @@ } catch { throw "Failed importing the Excel workbook '$Path' with worksheet '$WorksheetName': $_"; return } finally { + $EndRow = 0 + $EndColumn = 0 if ($Path) { $stream.close(); $ExcelPackage.Dispose() } } } diff --git a/__tests__/ImportExcelTests/ReadMultipleXLSXFiles.tests.ps1 b/__tests__/ImportExcelTests/ReadMultipleXLSXFiles.tests.ps1 new file mode 100644 index 0000000..b8631a3 --- /dev/null +++ b/__tests__/ImportExcelTests/ReadMultipleXLSXFiles.tests.ps1 @@ -0,0 +1,57 @@ +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'False Positives')] +Param() + +Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force + +Describe "Test reading multiple XLSX files of differernt row count" -Tag ReadMultipleXLSX { + It "Should find these xlsx files" { + Test-Path -Path $PSScriptRoot\rows05.xlsx | Should -BeTrue + Test-Path -Path $PSScriptRoot\rows10.xlsx | Should -BeTrue + } + + It "Should find two xlsx files" { + (Get-ChildItem $PSScriptRoot\row*xlsx).Count | Should -Be 2 + } + + It "Should get 5 rows" { + (Import-Excel $PSScriptRoot\rows05.xlsx).Count | Should -Be 5 + } + + It "Should get 10 rows" { + (Import-Excel $PSScriptRoot\rows10.xlsx).Count | Should -Be 10 + } + + It "Should get 15 rows" { + $actual = Get-ChildItem $PSScriptRoot\row*xlsx | Import-Excel + + $actual.Count | Should -Be 15 + } + + It "Should get 4 property names" { + $actual = Get-ChildItem $PSScriptRoot\row*xlsx | Import-Excel + + $names = $actual[0].psobject.properties.name + $names.Count | Should -Be 4 + + $names[0] | Should -BeExactly "Region" + $names[1] | Should -BeExactly "State" + $names[2] | Should -BeExactly "Units" + $names[3] | Should -BeExactly "Price" + } + + It "Should have the correct data" { + $actual = Get-ChildItem $PSScriptRoot\row*xlsx | Import-Excel + + # rows05.xlsx + $actual[0].Region | Should -BeExactly "South" + $actual[0].Price | Should -Be 181.52 + $actual[4].Region | Should -BeExactly "West" + $actual[4].Price | Should -Be 216.56 + + # rows10.xlsx + $actual[5].Region | Should -BeExactly "South" + $actual[5].Price | Should -Be 199.85 + $actual[14].Region | Should -BeExactly "East" + $actual[14].Price | Should -Be 965.25 + } +} \ No newline at end of file diff --git a/__tests__/ImportExcelTests/rows05.xlsx b/__tests__/ImportExcelTests/rows05.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3f54f30c98c963c9e7604c9f6cbab809b90fa0b3 GIT binary patch literal 2783 zcmZ`*c{r5&7a!YLldO|vhziLvvL%U2ilLY+4I#_e*O|#OH=^u?Y>ia1CS%JkZDhz~ zT-g~*$U1JQEFrq@=su6h?|0ApJn#2;|2XG)&*$?w=kqm%Gcogn*nsDV&m;56^Ce{v z1`y~369~iy0)cGwe0{JeAFRE3upbIzs}SVvRh`^n#02AMu}6_CGOD2Zc|%YF)Z&?T zLpnJ??^`0ds>at>O-?fZCKQ)(_#=63i|vFx^rh!&I;rJD-2I1f;9ChTQ6_SueTgYH zojiI+@wpi$C7Cle`Mi9i4LAQRqm^eHorQ^dT#doI2U zrUcGh8apKT?a#lj&eS2}7jIpYlQ`n4>eq;9HdfgmEt!zoWV_|yBTi-~Pjc$JV5_5X z4`!(jZv^=7UeVHilx-Co^#}( zHAroRhY$lqlDb~|<5)5Q6`;#Ak*lY94t5NGXW>w8@YI!iKeQS5lqmlcj5*K*P3W>vqvpR9zx(yrmSYnvA z1T*xZ9&q?BCOB#Zd2Ot1c30R<$DZzt4lfRqYzxn}$Yb?n9;UP{upQTTuYTB?6DGja zV-ehJ*n;KVXk@v^CBnQ6tLK~1UD0T}o22(ZO>7<6qJnFBWS*5&_mm*eHJ_31|HK3bdf&HUcx z>4>(4exN-B(B^*N4DwP8^hJ9*`ucj(v=e`^-J?l~D^wtNlZuU2{v#P$56^zqm=)NO zBywqpqoQ(Q1UDhEIFG^MEf5V8`p$pHB-}AMrw_nFg%Jc2 z{)Nde_UVz?Q9?;l2MwNR`{vo#8gp0gnAPH8v(-1CIs-MSbj;X8gI9wVWsBjFD@O&3u>PCyRM_&ziirqT!YG ziePak@VU9oYrSGZ#!Z)E4Qv&@6=Qo-!y8kWqd&sMnE7I>01we?o;!Ip-jZ zkEe!Kus*b8A0D$XkkD}lR>MBA$Qp2gVz7hP4T@GOJ62i{xirGR-KuL?^y9;OX|>UA z7c01G-crGhdu>|rCq=@A*)27j-OC$!VhU^DM&fYBBM>o*3t!F-Q@G{)4WN7 zv(YNt0cCw>6MN*$#nt_d4iz0d{VGwVYi-7={BfR+w1-$ffw=B+`+!BsLLC*Z#rWb+ z;wHgQi4!L(!!o)4J}n5ObP+jC2{)QhqnJ(wrq?8g*;BMJEr_n?63LQ7-nIMhAHFh9 zFwHGKqR~S&(~S*rwiGZf;!OR-{C#piR`RV>u(PbBJ7Z?-Sp3w1c3ySCnY1f0mA%~3 zS;x2-vMhT;!|!c-t5p$=@EIbw ziaoy*WF1xdDX%{+W_DA~MtE@qaVTM2Y;@3~foLi`3m0-d81<~G(M=wHRDGEUfr%Ro zn%caZ;i{_kJlvx>*GcSKD(cm-IsbSL9fk?eB3b-6cy`Ukd7r4~-XqtpxZ} zEZSA}lte_=-(e66%b}JrFI79fLjU@KvrDVYhr&~#-MgN6t^<8yJTR~5ToUk?@@<0IgdJz4+ z-W1NjC=WpJUl$<&8@l*E*P^`z=sl8V_`87wu%@&By@~WjLbK4_&;f>LkD=~Orr)zP zuh|WA;6?`||A+JJtwTS_w5_}wXkbtO`xF1OqxV*!*Bx!@cjGd6r^@aQ*qchv4NaK4 cvBdf-b+1fK;VeK=5Qr6c-U1M_veUl)0Zub@Gynhq literal 0 HcmV?d00001 diff --git a/__tests__/ImportExcelTests/rows10.xlsx b/__tests__/ImportExcelTests/rows10.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0ca23b912f46c2aebb3dd1eedb85fa508905fab0 GIT binary patch literal 2948 zcmZ{mc{tSj7stmowjpKLAVXQkGLx+<6^S&XYwXEZlW8z9n8|vH7D|?8vJ0UJj*IfF^mV7QmEq`kv=zS=_Uub~Lid>0=*6DC!1bAT@cH+r8xLUgwy zvu8G`8x8~JeHd4fS&aPa%=A;&q=hRNp?mgX4Fj9)TWt(>#6yx(TRb+-1}HOx87$Fb z=ZUrP5jit+1_k#G)J!u{=>6l35H!;@Y2Vx(Jyo*36|7gaDzwUZwmA;|Sz!N>SiQ=* z@!sQ%p%uBhDnD5sImp~<-MSW;f(bE~m?*L^IS$v#NSs$G3ZHUMUpH;;jKfPfWki1z zMj-`-xbdNW0-HJb{$?c`s5%?2DEssZ##|ui>2lsloz3ExVIbhRi)%zitl&A&m7DOl zejj+=IRkn6F*zdmg=Dm8*oChvYduw-?`|CGijOUifpo;)bt)Fb@edDn%nNBB^R3OL z6~;*O^*V*Oo@gWP`r0gz4%*HC8Qvf{ZN7A%;}*#x$4GJ2wap-+<&I;K0c|BbdVI4d zrh=}Z(`4KL=&uz2_PFdl@EX=WMc#ki?qiyD)n{N)3}!;_)8ri=#x9ZPTC4Ax=fpT^ zawqe1nuo4-%rn{P*|XE!!9K$-=!N2gacDdq$I(ub?Q6dl7${o0Xl;%dzyBy%sR4QS zQFB3PCuz6CkVsYa{7A%%>XP(%e$dte{Xt%)1^+^7FN^dBya&|t$oW&5+lqWP9#`?vh=B*CBvUikm1gg&{_I9>reF* zBXU<+s&Q*`^3HcP-@IE%c1uBKHlwfYJO= zo>#&c%Tb$3{7fUh(G~fO>#e0}Jqy|l*063%UEm(Wg9&~E!y5n&6Yk7^W)h1g7xuGR z81MoB3O|_qs6IED?@Fj3b#m~;d$rEII52xA(XK87K2v*1$?OdRoc*S)dvNM+oRPD= z#<}>stKOeC4wp}T#esWo>|cS)`A`(31a^BUoAAYNwD&+YWI*EaajNIrz? z*)etJYdhb>$ezHTu3j>LxWMf+^!ypB2wy^}bSYHA;cQF!I$c{2KI<3zr) z!UFvE&c zj?&g2^a?iMChkl%(=XOJQkhV;}Z)cW;_hhFK>+E^j&FW4UneX}6)Y%_aAC zCt`opU}JJhCEwV=kV@71P#BY>aJ)DRbPCUiYb5(C zsU~8=X2FUAW{8SPd7dVQGm@<8{xxfVOX@F*$R?JF#+g^;mBIpA)qSa`RQ2e4!?39U z^qKpnGMSX&xtwz_-}4VnC=`*ulwH3INhvdxxy4d^T&BUOub8-8$iG%5V&P<(SpU9B zGe+w#+ti~PZY63~3#{h`HdB))!nI=}T~7Po#UW<$V@OU84lTL?gf&0<6_nX<-1E zt?RqNSj2?UAZjW!^9eb|Yw$3k&Az*S4;eD#U$-Mm&HXI}RaCzBK<}KL`Hd)VXK9-U zqN$VoUsyYcke90A-kK0!-n<**NmDyt?=qH|PIJFr-6yVIpatS7aPEtaP2co4s-YsF z4PTB;h(+M(xeN2mgj2r-7x_

t9%1rW{29&CiA(p#p1!OS%B3<0>bMnF-ft)}U?* z3nTU_$!`@$2b`LyD1{lMELJ}5QBAXt4sxIIXQ~`r*=hjg);KCAtG#zIo7dLL}D~NmU)#is!RKp zCAP$_$3Avlr2bPEpR>UjZwF$qZvggtc`lO7kyLj3e?!nlPA(Nd{AD$D!%)UAVOGdKz?xR`9m>wxKWxn^jcH)Q64S$Xz)pw_U^Ob29h zYQRv+S-SbI8qk0qsw#a!Kxk-ED+juESDYM&Be;Bqi zLM(dIfl*??^y0{w8x9J|!>hwa^l#f5n;n<^pWSVH0PaD~*-Ey|mE9*?JIZ!P?rF!F z^IK-dF5<*p4!xLbBn=!ffe8KaN_?4SUEAp3dAMqDn;`T7SX$jZq8 literal 0 HcmV?d00001 From f478e8a134239eaff8e1eb58881f533a17bf2c71 Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 29 Apr 2022 22:11:24 -0400 Subject: [PATCH 108/140] Add Enable-ExcelAutoFilter and Enable-ExcelAutofit example --- Examples/OpenExcelPackage/EnableFeatures.ps1 | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Examples/OpenExcelPackage/EnableFeatures.ps1 diff --git a/Examples/OpenExcelPackage/EnableFeatures.ps1 b/Examples/OpenExcelPackage/EnableFeatures.ps1 new file mode 100644 index 0000000..2d3d263 --- /dev/null +++ b/Examples/OpenExcelPackage/EnableFeatures.ps1 @@ -0,0 +1,28 @@ +# How to use Enable-ExcelAutoFilter and Enable-ExcelAutofit + +try { Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 } catch { throw ; return } + +$data = ConvertFrom-Csv @" +RegionInfo,StateInfo,Units,Price +West,Texas,927,923.71 +North,Tennessee,466,770.67 +East,Florida,520,458.68 +East,Maine,828,661.24 +West,Virginia,465,053.58 +North,Missouri,436,235.67 +South,Kansas,214,992.47 +North,North Dakota,789,640.72 +South,Delaware,712,508.55 +"@ + +$xlfile = "$PSScriptRoot\enableFeatures.xlsx" +Remove-Item $xlfile -ErrorAction SilentlyContinue + +$data | Export-Excel $xlfile + +$excel = Open-ExcelPackage $xlfile + +Enable-ExcelAutoFilter -Worksheet $excel.Sheet1 +Enable-ExcelAutofit -Worksheet $excel.Sheet1 + +Close-ExcelPackage $excel -Show \ No newline at end of file From 59e40d62d0a9d05534ee7480e9e4389ddce9bd2d Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 30 Apr 2022 07:05:04 -0400 Subject: [PATCH 109/140] bump version --- ImportExcel.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index c6c22be..e6934d7 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.4.2' + ModuleVersion = '7.5.0' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' From e55dfdd10ed97d27ecece4baff7ceb2bc7db6b6a Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 30 Apr 2022 07:05:10 -0400 Subject: [PATCH 110/140] Update changes --- changelog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.md b/changelog.md index c27429a..0381954 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,9 @@ +# v7.5.0 + +## Fixes + +- Importing multiple files with Import-Excel by pipeline uses only the first file for the row count https://github.com/dfinke/ImportExcel/issues/1172 + # v7.4.2 - Thank you [James Mueller](https://github.com/jamesmmueller) Updated `ConvertFrom-ExcelToSQLInsert` to handle single quotes in the SQL statement. From 634aaacc55a71ea06942af0139c34c860edbc7b4 Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 30 Apr 2022 07:58:55 -0400 Subject: [PATCH 111/140] update change log --- changelog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.md b/changelog.md index 0381954..8959cff 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,12 @@ - Importing multiple files with Import-Excel by pipeline uses only the first file for the row count https://github.com/dfinke/ImportExcel/issues/1172 +## New Features + +- Import-Excel now supports importing multiple sheets. It can either return a dictionary of all sheets, or as a single array of all sheets combined. + - `Import-Excel $xlfile *` # reads all sheets, returns all data in a dictionary + - `Import-Excel $xlfile * -NotAsDictionary` # reads all sheets, returns all data in a single array + # v7.4.2 - Thank you [James Mueller](https://github.com/jamesmmueller) Updated `ConvertFrom-ExcelToSQLInsert` to handle single quotes in the SQL statement. From b2119f08f55860b477bf89a48f528464a3ff2307 Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 30 Apr 2022 07:59:22 -0400 Subject: [PATCH 112/140] add example for importing an xlsx and multiple sheets --- .../ImportMultipleSheetsAsArray.ps1 | 7 +++++++ .../ImportMultipleSheetsAsHashtable.ps1 | 9 +++++++++ Examples/Import-Excel/yearlySales.xlsx | Bin 0 -> 54899 bytes 3 files changed, 16 insertions(+) create mode 100644 Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 create mode 100644 Examples/Import-Excel/ImportMultipleSheetsAsHashtable.ps1 create mode 100644 Examples/Import-Excel/yearlySales.xlsx diff --git a/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 b/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 new file mode 100644 index 0000000..0f46c09 --- /dev/null +++ b/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 @@ -0,0 +1,7 @@ +Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force + +$xlfile = "$PSScriptRoot\yearlySales.xlsx" + +$result = Import-Excel $xlfile * -NotAsDictionary + +$result | Measure-Object \ No newline at end of file diff --git a/Examples/Import-Excel/ImportMultipleSheetsAsHashtable.ps1 b/Examples/Import-Excel/ImportMultipleSheetsAsHashtable.ps1 new file mode 100644 index 0000000..d99c61c --- /dev/null +++ b/Examples/Import-Excel/ImportMultipleSheetsAsHashtable.ps1 @@ -0,0 +1,9 @@ +Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force + +$xlfile = "$PSScriptRoot\yearlySales.xlsx" + +$result = Import-Excel $xlfile * + +foreach ($sheet in $result.Values) { + $sheet +} \ No newline at end of file diff --git a/Examples/Import-Excel/yearlySales.xlsx b/Examples/Import-Excel/yearlySales.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d30993a1d57932fef39a8e6be132d9e49914247c GIT binary patch literal 54899 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 a|Fb&dsWLtR=2sNJryCCo3p$AT@BaWQ9!4Di literal 0 HcmV?d00001 From ba145112548047d9b2bd9a5a091cce2ff1502a6a Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 30 Apr 2022 08:21:24 -0400 Subject: [PATCH 113/140] update changelog --- changelog.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 8959cff..4d64cda 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,4 @@ # v7.5.0 - ## Fixes - Importing multiple files with Import-Excel by pipeline uses only the first file for the row count https://github.com/dfinke/ImportExcel/issues/1172 @@ -9,6 +8,10 @@ - Import-Excel now supports importing multiple sheets. It can either return a dictionary of all sheets, or as a single array of all sheets combined. - `Import-Excel $xlfile *` # reads all sheets, returns all data in a dictionary - `Import-Excel $xlfile * -NotAsDictionary` # reads all sheets, returns all data in a single array +- Added helper functions. Useful for working with an Excel package via `Open-ExcelPackage` or `-PassThru` + - `Enable-ExcelAutoFilter` + - `Enable-ExcelAutofit` + - `Get-ExcelSheetDimensionAddress` # v7.4.2 From d4ebc9e95d2ce17529d4de51ecc01048dc6ac43c Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 30 Apr 2022 13:17:20 -0400 Subject: [PATCH 114/140] Use explicit parameter names --- Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 | 2 +- Examples/Import-Excel/ImportMultipleSheetsAsHashtable.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 b/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 index 0f46c09..74e175f 100644 --- a/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 +++ b/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 @@ -2,6 +2,6 @@ Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force $xlfile = "$PSScriptRoot\yearlySales.xlsx" -$result = Import-Excel $xlfile * -NotAsDictionary +$result = Import-Excel -Path $xlfile -WorksheetName * -NotAsDictionary $result | Measure-Object \ No newline at end of file diff --git a/Examples/Import-Excel/ImportMultipleSheetsAsHashtable.ps1 b/Examples/Import-Excel/ImportMultipleSheetsAsHashtable.ps1 index d99c61c..d432349 100644 --- a/Examples/Import-Excel/ImportMultipleSheetsAsHashtable.ps1 +++ b/Examples/Import-Excel/ImportMultipleSheetsAsHashtable.ps1 @@ -2,7 +2,7 @@ Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force $xlfile = "$PSScriptRoot\yearlySales.xlsx" -$result = Import-Excel $xlfile * +$result = Import-Excel -Path $xlfile -WorksheetName * foreach ($sheet in $result.Values) { $sheet From aea90aa8d608bebec638c6ae43518eea03d9cc85 Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 3 May 2022 17:53:58 -0400 Subject: [PATCH 115/140] Fix reading multiple sheets in the xlsx where row/col count is diff --- Public/Import-Excel.ps1 | 6 ++++-- .../ImportExcelReadSheets.tests.ps1 | 10 ++++++++++ __tests__/ImportExcelTests/construction.xlsx | Bin 0 -> 25337 bytes 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 __tests__/ImportExcelTests/construction.xlsx diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index b9574e7..fe2df9f 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -134,6 +134,8 @@ $xlBook = [Ordered]@{} foreach ($sheet in $Worksheet) { + $EndRow = 0 + $EndColumn = 0 $targetSheetname = $sheet.Name $xlBook["$targetSheetname"] = @() #region Get rows and columns @@ -233,8 +235,8 @@ } catch { throw "Failed importing the Excel workbook '$Path' with worksheet '$WorksheetName': $_"; return } finally { - $EndRow = 0 - $EndColumn = 0 + # $EndRow = 0 + # $EndColumn = 0 if ($Path) { $stream.close(); $ExcelPackage.Dispose() } if ($NotAsDictionary) { diff --git a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 index 92d1589..6d70e85 100644 --- a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 +++ b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 @@ -59,5 +59,15 @@ Describe 'Different ways to import sheets' -Tag ImportExcelReadSheets { $group[0].Name | Should -BeExactly 'April' $group[1].Name | Should -BeExactly 'June' } + + It "Should read multiple sheets with diff number of rows correctly" { + $xlFilename = "$PSScriptRoot\construction.xlsx" + + $actual = Import-Excel $xlFilename 2015, 2016 + $actual.keys.Count | Should -Be 2 + + $actual["2015"].Count | Should -Be 12 + $actual["2016"].Count | Should -Be 1 + } } } \ No newline at end of file diff --git a/__tests__/ImportExcelTests/construction.xlsx b/__tests__/ImportExcelTests/construction.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..befd778debd102b3173b960ef611103c239d2308 GIT binary patch literal 25337 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 lXIU3MHTl~xbr3Ml7bhwz3TOc7AR& Date: Tue, 3 May 2022 17:54:16 -0400 Subject: [PATCH 116/140] bump version --- ImportExcel.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index 9cb72ff..d64c839 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.5.0' + ModuleVersion = '7.5.1' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' From 79e5bdf8ba42e482c54c9f6df8cd45b5d4ca690d Mon Sep 17 00:00:00 2001 From: dfinke Date: Tue, 3 May 2022 17:54:21 -0400 Subject: [PATCH 117/140] update --- changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.md b/changelog.md index 4d64cda..7ca9f2b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,5 @@ +# v7.5.1 +- Fixed `Import-Excel` - Reset `EndRow` and `EndColumn` in the correct place. # v7.5.0 ## Fixes From 415be5bca385fb9d32956873db839b27bebe95af Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 4 May 2022 18:32:19 -0400 Subject: [PATCH 118/140] bump version --- ImportExcel.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index d64c839..d47e882 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.5.1' + ModuleVersion = '7.5.2' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' From 0b3b382c4e4a3b387a33e99f7a13a8341f694f74 Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 4 May 2022 18:32:27 -0400 Subject: [PATCH 119/140] update --- changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.md b/changelog.md index 7ca9f2b..3e4eace 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,6 @@ +# v7.5.2 +- Changed the switch `-NotAsDictionary` to `-Raw`. Works with `-Worksheetname *` reads all the sheets in the xlsx file and returns an array. + # v7.5.1 - Fixed `Import-Excel` - Reset `EndRow` and `EndColumn` in the correct place. # v7.5.0 From 4fa34ae257ede65d4899f3b051ffa75ea3fdc699 Mon Sep 17 00:00:00 2001 From: dfinke Date: Wed, 4 May 2022 18:33:19 -0400 Subject: [PATCH 120/140] Rename switch NotAsDictionary to Raw --- Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 | 2 +- Public/Import-Excel.ps1 | 4 ++-- .../ImportExcelTests/ImportExcelReadSheets.tests.ps1 | 11 ++++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 b/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 index 74e175f..31242b0 100644 --- a/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 +++ b/Examples/Import-Excel/ImportMultipleSheetsAsArray.ps1 @@ -2,6 +2,6 @@ Import-Module $PSScriptRoot\..\..\ImportExcel.psd1 -Force $xlfile = "$PSScriptRoot\yearlySales.xlsx" -$result = Import-Excel -Path $xlfile -WorksheetName * -NotAsDictionary +$result = Import-Excel -Path $xlfile -WorksheetName * -Raw $result | Measure-Object \ No newline at end of file diff --git a/Public/Import-Excel.ps1 b/Public/Import-Excel.ps1 index fe2df9f..819fa0c 100644 --- a/Public/Import-Excel.ps1 +++ b/Public/Import-Excel.ps1 @@ -37,7 +37,7 @@ [ValidateNotNullOrEmpty()] [String]$Password, [Int[]]$ImportColumns, - [Switch]$NotAsDictionary + [Switch]$Raw ) end { $sw = [System.Diagnostics.Stopwatch]::StartNew() @@ -239,7 +239,7 @@ # $EndColumn = 0 if ($Path) { $stream.close(); $ExcelPackage.Dispose() } - if ($NotAsDictionary) { + if ($Raw) { foreach ($entry in $xlbook.GetEnumerator()) { $entry.Value } diff --git a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 index 6d70e85..1b8dfad 100644 --- a/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 +++ b/__tests__/ImportExcelTests/ImportExcelReadSheets.tests.ps1 @@ -50,7 +50,7 @@ Describe 'Different ways to import sheets' -Tag ImportExcelReadSheets { } It 'Should return an array not a dictionary' { - $actual = Import-Excel $xlFilename april, june -NotAsDictionary + $actual = Import-Excel $xlFilename april, june -Raw $actual.Count | Should -Be 200 $group = $actual | Group-Object month -NoElement @@ -69,5 +69,14 @@ Describe 'Different ways to import sheets' -Tag ImportExcelReadSheets { $actual["2015"].Count | Should -Be 12 $actual["2016"].Count | Should -Be 1 } + + It "Should read multiple sheets with diff number of rows correctly and flatten it" { + $xlFilename = "$PSScriptRoot\construction.xlsx" + + $actual = Import-Excel $xlFilename 2015, 2016 -Raw + + $actual.Count | Should -Be 13 + } + } } \ No newline at end of file From 390aca0496498a364a53f15529f65dbc64d5b815 Mon Sep 17 00:00:00 2001 From: dfinke Date: Thu, 5 May 2022 16:58:15 -0400 Subject: [PATCH 121/140] update --- README.md | 1313 ++------------------------- images/SalesData.png | Bin 0 -> 10594 bytes images/SalesDataChart.png | Bin 0 -> 36153 bytes images/SalesDataChartPivotTable.png | Bin 0 -> 243621 bytes images/logo.png | Bin 0 -> 22972 bytes 5 files changed, 95 insertions(+), 1218 deletions(-) create mode 100644 images/SalesData.png create mode 100644 images/SalesDataChart.png create mode 100644 images/SalesDataChartPivotTable.png create mode 100644 images/logo.png diff --git a/README.md b/README.md index b614b3b..d7c5f48 100644 --- a/README.md +++ b/README.md @@ -1,1248 +1,125 @@ -# PowerShell + Excel = Better Together +# PowerShell and Excel +![](images/logo.png) -Automate Excel via PowerShell without having Excel installed. Runs on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier. +# Overview -
+Automate Excel with PowerShell without having Excel installed. Works on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier. -[![](https://img.shields.io/powershellgallery/v/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) [![](https://img.shields.io/powershellgallery/dt/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) [![](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/dfinke/ImportExcel/tree/70ab9e46c776e96fb287682d5b9b4b51a0ec3bac/LICENSE.txt) - -
- -| CI System | Environment | Status | -| :--- | :--- | :--- | -| Azure DevOps | Windows | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=Windows)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) | -| Azure DevOps | Windows \(Core\) | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=WindowsPSCore)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) | -| Azure DevOps | Ubuntu | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=Ubuntu)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) | -| Azure DevOps | macOS | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=macOS)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) | - -
- -Install from the [PowerShell Gallery](https://www.powershellgallery.com/packages/ImportExcel/). +# Basic Usage +## Installation ```powershell Install-Module -Name ImportExcel ``` -### Donation -If this project helped you reduce the time to get your job done, let me know, send a coffee. - -
- -[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UCSB9YVPFSNCY) - -![](https://media.giphy.com/media/hpXxJ78YtpT0s/giphy.gif) - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/testimonial.png) - -## How to Videos - -* [PowerShell Excel Module - ImportExcel](https://www.youtube.com/watch?v=fvKKdIzJCws&list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq) - -Installation - - -**PowerShell V5 and Later** - -You can install the `ImportExcel` module directly from the PowerShell Gallery - -* \[Recommended\] Install to your personal PowerShell Modules folder - - ```text - Install-Module ImportExcel -scope CurrentUser - ``` - -* \[Requires Elevation\] Install for Everyone \(computer PowerShell Modules folder\) - - ```text - Install-Module ImportExcel - ``` - -## Continuous Integration Updates - -Big thanks to [Illy](https://github.com/ili101) for taking the Azure DevOps CI to the next level. Improved badges, improved matrix for cross platform OS testing and more. - -Plus, wiring the [PowerShell ScriptAnalyzer Excel report](https://github.com/dfinke/ImportExcel/pull/590#issuecomment-488659081) we built into each run as an artifact. - -![](.gitbook/assets/ScriptAnalyzerReport.png) - -## What's new 7.1.3 - -- Changed to `ProviderPath`. Thanks [Trevor Walker](https://github.com/sporkabob) - -## What's new 7.1.2 - -- `Get-ExcelFileSummary` - Gets summary information on an Excel file like number of rows, columns, and more - -``` -dir . -r *.xlsx | Get-ExcelFileSummary | ft - -ExcelFile WorksheetName Rows Columns Address Path ---------- ------------- ---- ------- ------- ---- -Grades.xlsx Sheet1 21 3 A1:C21 D:\temp\ExcelYouTube\Grades -GradesAverage.xlsx Sheet1 21 5 A1:E21 D:\temp\ExcelYouTube\Grades -AllShifts.xlsx Sheet1 21 2 A1:B21 D:\temp\ExcelYouTube\SeparateData -Shift_1.xlsx Sheet1 10 2 A1:B10 D:\temp\ExcelYouTube\SeparateData -Shift_2.xlsx Sheet1 8 2 A1:B8 D:\temp\ExcelYouTube\SeparateData -Shift_3.xlsx Sheet1 5 2 A1:B5 D:\temp\ExcelYouTube\SeparateData -Shifts.xlsx Shift_1 10 2 A1:B10 D:\temp\ExcelYouTube\SeparateData -Shifts.xlsx Shift_2 8 2 A1:B8 D:\temp\ExcelYouTube\SeparateData -``` - -## What's new 7.1.1 - -* Merged [Nate Ferrell](https://github.com/scrthq)'s Linux fix. Thanks! -* Moved `Export-MultipleExcelSheets` from psm1 to Examples/Experimental -* Deleted the CI build in Appveyor -* Thank you [Mikey Bronowski](https://github.com/MikeyBronowski) for - * Multiple sweeps - * Standardising casing of parameter names, and variables - * Plus updating > 50 of the examples and making them consistent. - -## What's new 7.1.0 - -Fixes, Updates and new Examples - -#### Fixed - -* Odd behavior on the return of Import-Excel function [https://github.com/dfinke/ImportExcel/issues/792](https://github.com/dfinke/ImportExcel/issues/792) -* Export-Excel -FreezeTopRow with -Title [https://github.com/dfinke/ImportExcel/issues/795](https://github.com/dfinke/ImportExcel/issues/795) -* Not importing when first row contains a 0 in a column [https://github.com/dfinke/ImportExcel/issues/802](https://github.com/dfinke/ImportExcel/issues/802) - -#### Updated - -* Add `-AsDate` support to `Import-Excel` and `ConvertFrom-ExcelSheet` - -#### New Examples - -| PS1 | Description | Link | -| :--- | :--- | :--- | -| Pester-To-XLSx | Runs Pester, collects the results, enriches it, and exports it to Excel | [Pester-To-XLSx.ps1](https://github.com/dfinke/ImportExcel/blob/fe68ddbb0dd86e9fd1f3bfe01c4d2b9ce5509510/Examples/Pester-To-XLSx.ps1) | -| DSUM | Sums up the numbers in a field \(column\) of records in a list or database that match conditions that you specify. | [DSUM.ps1](https://github.com/dfinke/ImportExcel/blob/12fa49e3142af2178ae1c6b18d8c757af0d629ac/Examples/ExcelBuiltIns/DSUM.ps1) | -| VLookup | Setups up a sheet, you enter the name of an item and the amount is looked up | [VLOOKUP.ps1](https://github.com/dfinke/ImportExcel/blob/e42f42fde92ca636af22252b753a8329f48e15f1/Examples/ExcelBuiltIns/VLOOKUP.ps1) | - -## What's new 7.0.1 - -More infrastructure improvements. - -* Refine pipeline script analysis -* Improve artifacts published -* Add manifest \(psd1\) checks - -## What's new 7.0.0 - -### Refactor - -* Remove all functions from the `psm1` -* Move functions into public subdirectory -* Align TDD and continuous integration workflow for this refactor -* Move help from functions to mdHelp and use [PlatyPS](https://www.powershellgallery.com/packages/platyPS) to generate external help file - -Thanks to [James O'Neill](https://twitter.com/jamesoneill) for the refactor and [Illy](https://twitter.com/ili_z) on the continuous integration. - -## What's new 6.5.3 - -Thanks again to the community for making this module even better. - -* [Fix import excel headers](https://github.com/dfinke/ImportExcel/pull/713) -* Numerous improvements for DataTables and exporting it to Excel [James O'Neill](https://twitter.com/jamesoneill) - * Names, styles, proper appending -* Handles marking the empty row on an empty table as dummy row -* Re-work code based on linting recommendations -* Update existing tests and add more -* Support PipelineVariable thanks to [Luc Dekens](https://twitter.com/LucD22) for reporting and [Ili](https://twitter.com/ili_z) for the PR -* Fix quoting in ConvertFromExcelToSQLInsert [beckerben](https://github.com/beckerben) - -## What's new 6.5.2 - -Thank you [uSlackr](https://github.com/uSlackr)ill - -* Fixes Column order issue \(plus tests\) for `Get-ExcelColumnName` - -Thank you [jhoneill](https://github.com/jhoneill) - -* Added -Force to Send-SQLDataToExcel so it sends something even if no rows are returned. \(see [\#703](https://github.com/dfinke/ImportExcel/issues/703)\) -* Added -asText to import-Excel see \(\#164\)\[[https://github.com/dfinke/ImportExcel/issues/164](https://github.com/dfinke/ImportExcel/issues/164)\] and multiple others -* Linux. Now set an environment variable if the support needed for Autosize is present, and use that Environment variable to decide to skip autosize operations. -* Fixed tests which needed autosize to work so they skip of the environment variable is set. -* Fixed another break where on azure the module never loaded. -* Add a comment to ci.ps1 re better .NET version detection and left some commented out code. - -Other - -* Added the example [ReadAllSheets.ps1](https://github.com/dfinke/ImportExcel/tree/master/Examples/ReadAllSheets) based on this thread [https://github.com/dfinke/ImportExcel/issues/678](https://github.com/dfinke/ImportExcel/issues/678) - -## What's new 6.5.0 - -This is now using the latest version of EPPlus. Unit tests are updated and passing, if you hit problems, please open an issue. You can rollback to an older version from the PowerShell Gallery if you are blocked. - -* Unit tests were updated and fixed -* "Set-WorksheetProtection" is now switched on -* Made a change to make Set-Excel range more friendly when Auto Sizing on non-windows platforms -* Fixed - Windows only tests don't attempt to run on non-windows systems -* Tests based on Get-Process don't attempt to run if <20 processes are returned -* If $env:TEMP is not set \(as will be the case on Linux\) -* Join-Path if used so paths are built with / or with as suits the OS where the test is running. -* Excel Sparklines now supported, check out the examples [SalesByQuarter](https://github.com/dfinke/ImportExcel/blob/master/Examples/Sparklines/SalesByQuarter.ps1) and [Sparklines](https://github.com/dfinke/ImportExcel/blob/master/Examples/Sparklines/Sparklines.ps1). - -![](.gitbook/assets/Sparklines.png) - -## What's new 6.2.4 - -Sensible parameter defaults, make your life easier and gets things done faster. - -* Thank you to [DomRRuggeri](https://github.com/DomRRuggeri) for the initial Out-Excel PR and kicking off the conversation on the improvements. -* Thank you to [ili101](https://github.com/ili101) for refactoring and improving the defaults, and adding the tests for parameters. -* Creates a table, with filtering -* Chooses a `TableStyle` -* Displays the Excel spreadsheet automatically - -```text -Get-Process | select Company, Name, Handles | Export-Excel -``` - -![image](.gitbook/assets/ImproveNowDefaults.png) - -## What's new 6.2.3 - -Thank you [jhoneill](https://github.com/jhoneill). - -* Refactored copy sheet and added pipe support -* Add `ClearAll` to `Set-ExcelRange` -* Fix broken test & regression for `passwords` - * **Note**: Passwords do not work on `pwsh`. The EPPlus library does not support these dotnet core APIs at this time. - -## What's new 6.2.2 - -* Added requested feature, chart trendlines. - * [Example PowerShell script](https://github.com/dfinke/ImportExcel/blob/master/Examples/Charts/NumberOfVisitors.ps1) - -![](.gitbook/assets/ChartTrendlines.png) - -* Fixed Import-Excel and relative path issue, added unit tests. - -## What's new 6.2.0 - -Thank you to [James O'Neill](https://github.com/jhoneill) - -* Fixed, Import-Excel can read xlsx files even if already open in Excel -* Added `New-ExcelStyle`, plus `-Style` to `Export-Excel` and `-Merge` to `Set-ExcelRange` -* Added [Style Examples](https://github.com/dfinke/ImportExcel/tree/master/Examples/Styles) - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/NewExcelStyle.png) - -## What's new 6.1.0 - -Thank you to [James O'Neill](https://github.com/jhoneill) - -* Instead of specifying a path provides an Excel Package object \(from `Open-ExcelPackage`\), using this avoids re-reading the whole file when importing multiple parts of it. To allow multiple read operations `Import-Excel` does NOT close the package, and you should use `Close-ExcelPackage -noSave` to close it. - -## What's new 6.0.0 - -Thank you to [James O'Neill](https://github.com/jhoneill) for the optimizations, and refactoring leading to a _**~10x**_ speed increase. Thanks to [ili101](https://github.com/ili101) for earlier PRs that provided the ground work for this. - -* Performance improvement to `Export-Excel` see [\#506](https://github.com/dfinke/ImportExcel/issues/506) and [\#555](https://github.com/dfinke/ImportExcel/issues/555). This has meant taking code in Add-CellValue back into process block of `Export-Excel`, as the overhead of calling the function was a lot greater than time executing the code inside it. [Blog post to follow](https://jamesone111.wordpress.com/). Some tests are showing a _**~10x**_ speed increase. [\#572](https://github.com/dfinke/ImportExcel/issues/572) was about a broken \#region tag in this part of the code and that has been cleaned up in the process. -* `Export-Excel` now has an -InputObject parameter \(this was previously -TargetData , which is now an alias for InputObject\). If the `inputobject` is an array, each item will be inserted, so you can run `export-excel -inputobject $x` rather than `$x | Export-Excel`, and if it is a `system.data.datatable` object it will be inserted directly rather than cell-by-cell. `Send-SQLDataToExcel` takes advantage of this new functionality. There are simple tests for these new items -* `Export-Excel` previously assumed `-Now` if there were no other parameters, it will now assume `-Now` if there is no `-Path` or `-ExcelPackage`. The .PSD1 file now itemizes the items exported by the module [\#557](https://github.com/dfinke/ImportExcel/issues/557) - -## What's new 5.4.5 - -Thank you to [James O'Neill](https://github.com/jhoneill) for the great additions. - -* Modified Send-SQLDataToExcel so it creates tables and ranges itself; previously it relied on export-excel to do this which cause problems when adding data to an existing sheet \(\#555\) -* Added new command Add-ExcelDataValidation which will apply different data-validation rules to ranges of cells -* Changed the export behavior so that \(1\) attempts to convert to a number only apply if the the value was a string; \(2\) Nulls are no longer converted to an empty string \(3\) there is a specific check for URIs and not just text which is a valid URI. Using UNC names in hyperlinks remains problematic. -* Changed the behavior of AutoSize in export excel so it only applies to the exported columns. Previously if something was exported next to pre-existing data, AutoSize would resize the whole sheet, potentially undoing things which had been set on the earlier data. If anyone relied on this behavior they will need to explicitly tell the sheet to auto size with $sheet.cells.autofitColumns. \(where $sheet points to the sheet, it might be $ExcelPackage.Workbook.Worksheets\['Name'\]\) -* In Compare-Worksheet,the Key for comparing the sheets can now be written as a hash table with an expression - it is used with a Group-Object command so if it is valid in Group-Object it should be accepted; this allows the creation of composite keys when data being compared doesn't have a column which uniquely identifies rows. -* In Set-ExcelRange , added a 'Locked' option equivalent to the checkbox on the Protection Tab of the format cells dialog box in Excel. -* Created a Set-WorksheetProtection function. This gives the same options the protection dialog in Excel but is 0.9 release at the moment. - -### New Example - -* Added [MutipleValidations.ps1](https://github.com/dfinke/ImportExcel/blob/master/Examples/ExcelDataValidation/MutipleValidations.ps1). Culled from the `tests`. - -## What's new 5.4.4 - -* Fix issue when only a single property is piped into Export-Excel -* Fix issue in `Copy-ExcelWorksheet`, close the `$Stream` - -## What's new 5.4.3 - -* Added Remove-Worksheet: Removes one or more worksheets from one or more workbooks - -## What's new 5.4.2 - -* Added parameters -GroupDateRow and -GroupDatePart & -GroupNumericRow, -GroupNumericMin, -GroupNumericMax and -GroupNumericInterval - - to Add-PivotTable and New-PivotTableDefinition. The date ones gather dates of the same year and/or quarter and/or month and/or day etc. - - the number ones group numbers into bands, starting at Min, and going up steps specified by Interval. Added tests and help for these. - -* Set-ExcelRow and Set-ExcelColumn now check that the worksheet name they passed exists in the workbook. - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/cf964e3e4f761ca4058c4a4b809e2206b16709da/images/GroupingNumeric.png) - -## What's new 5.4.0 - -* Thank you to Conrad Agramont, Twitter: [@AGramont](https://twitter.com/@AGramont) for the `AddMultiWorkSheet.ps1` example. Much appreciated! -* Fixed several more bugs where parameters were ignored if passed a zero value -* Fixed bug where chart series headers could not come form a cell reference \(=Sheet1!Z10 now works as a header reference\) -* Add-Chart will now allow a single X range, or as many X ranges as there are Y ranges. -* Merge-MultipleSheets is more robust. -* Set-ExcelRow and Set-ExcelColumn trap attempts to process a sheet with no rows/columns. -* Help has been proof-read \(thanks to Mrs. @Jhoneill !\). - -## What's new 5.3.4 - -* HotFix for parameter PivotTableStyle should be PivotTableStyle [https://github.com/dfinke/ImportExcel/issues/453](https://github.com/dfinke/ImportExcel/issues/453) - -## What's new 5.3.3 - -* Thank you to \(lazywinadmin\)\[[https://github.com/lazywinadmin](https://github.com/lazywinadmin)\] - Expand aliases in examples and elsewhere -* In Export-Excel fixed a bug where -AutoNameRange on pre-existing data included the header in the range. -* In Export-Excel fixed a bug which caused a zero, null, or empty string in a list of simple objects to be skipped. -* In Export-Excel improved the behaviour when a new worksheet is created without data, and Tables etc are added to it. -* In Join-Worksheet: added argument completer to -TitleBackgroundColor and set default for -TitleBackgroundStyle to 'Solid'. -* In Add-Excel chart, New-ExcelChart, tests and Examples fixed mis-spelling of "Position" -* In Send-SqlDataToExcel: improved robustness of check for no data returned. -* In Set-ExcelColumn: -column can come from the pipeline \(supporting an array introduces complications for supporting script blocks\); -AutoNameRange no longer requires heading to specified \(so you can do 1..10 \| Set-ExcelColumn -AutoNameRange \); In Set-ExcelRow: -Row can come from the pipeline -* Improved test coverage \(back over 80%\). -* Help and example improvements. In "Index - music.ps1" the module for querying the index can be downloaded from PowerShell gallery \#requires set to demand it. In SQL+FillColumns+Pivot\example2.ps1 the GetSQL module can be downloaded and \#Requires has been set. The F1 results spreadsheet is available from one drive and a link is provided. -* Added Azure DevOps continuous integration and badges - -## What's new in Release 5.3 - -* Help improvements and tidying up of examples and extra examples -* Open-Excel Package and Add-Worksheet now add worksheets as script properties so `$Excel = Open-ExcelPackage -path test.xlsx ; $excel.sheet1` will return the sheet named "sheet1" `$Excel.SheetName` is a script property which is defined as `$this.workbook.worksheets["Sheetname"]` -* Renamed Set-Column to `Set-ExcelColumn`, Set-Row to `Set-ExcelRow`, and Set-Format, to `Set-ExcelRange`. Added aliases so the old names still work. -* `Set-ExcelRange` \(or set-Format\) used "Address" and "Range" incorrectly. There is now a single parameter `-Range`, with an alias of "Address". If the worksheet parameter is present, the function accepts a string specifying cells \("A1:Z10"\) or a the name of range. Without the worksheet it accepts an object representing a named range or a Table; or a tables's address, or part of the worksheet.cells collection. -* `Add-ConditionalFormatting`: Used "address" correctly, and it will accept ranges in the address parameter \(range is now an alias for address\). It now wraps conditional value strings in quotes when needed \(for = <= >= operations string needs to be in double quotes see issue \#424\). Parameter intellisense has been improved. There are new parameters: `-StopIfTrue` and `-Priority` and support for using the `-Reverse` parameter with Color-scale rules \(issue \#430\). Booleans in the sheet are now supported as the value for a condition. Also brought the two different kinds of condition together inside Export-Excel, and fixed a bug where named-ranges didn't work in some places. In `New-ConditionalText`, more types of conditional format are supported, and the argument completer for -ConditionalTextColor was missing and has been added. -* Improved handling of hyperlinks in `Export-Excel` \(see issue \#426\)s -* `Export-Excel` has better checking of Table and PivotTable names \(for uniqueness\) and a new test in quick charts that there is suitable data for charting. It also accepts hash tables for chart, pivot table and conditional formatting parameters which are splatted into the functions which add these. -* Moved logic for adding a named-range out of Export-Excel and into a new function named `Add-ExcelName`, and logic for adding a table into a function named `Add-ExcelTable`; this is to make it easier to do these things independently of Export-Excel, but minimize duplication. The Add-ExcelTable command has extra parameters to toggle the options from table tools toolbar \(show totals etc.\) and set options in the totals row. -* Moved PivotTable Functions out of Export-Excel.PS1 into their own file and moved Add-ExcelChart out of Export-Excel.ps1 into New-ExcelChart.ps1 -* Fixed bug in Merge-MultipleSheets where background pattern was set to None, making background color invisible. -* Fixed issues where formatting could be reset when using Export-Excel to manipulate an existing sheet without appending data; this applied to number-formats and tables. -* `Add-PivotTable` has some new parameters `-PassThru` returns the pivot table \(e.g. to allow names /sort orders of data series to be tweaked \) `-Address` allows Pivot to be placed on an existing sheet; `-PivotTableStyle` allows a change from "Medium6", `-PivotNumberFormat` formats data cells. It is more flexible about how the source data is specified - copying the range options in Set-ExcelRange. `Add-ExcelChart` is now used for creating PivotCharts, and `-PivotChartDefinition` allows a definition created with `New-ExcelChartDefinition` to be used when setting up a PivotTable. This opens up all the things that Add-ExcelChart can do without duplicating the parameters on Add-Pivot table and Export-Excel. Definition, TableStyle, Numberformat and ChartDefiniton can be used in `New-PivotTableDefinition` . -* `Add-ExcelChart` now supports -PassThru to return the chart for tweaking after creation; there is now a -PivotTable parameter to allow Add-PivotTable to call the code in Add-ExcelChart. And in `New-ExcelChartDefinition` Legend parameters \(for size, bold & position \) are now supported -* ChartDefinition and conditional formatting parameters can now be hashtables - anything that splats Add-ExcelChart or Add-ConditionalFormatting, it should be acceptable as a definition. - -## What's new in Release 5.2 - -* Value does not need to be mandatory in Set-Row or Set-Column, also tidied their parameters a little. -* Added support for array formulas in Set-Format \(it really should be set range now that it sets values, formulas and hyperlinks - that can go on the to-do list \) -* Fixed a bug with -Append in Export-Excel which caused it to overwrite the last row if the new data was a simple type. -* NumberFormat in Export-Excel now sets the default for on a new / blank sheet; but \[still\] sets individual cells when adding to a sheet -* Added support for timespans in Export excel ; set as elapsed hours, mins, secs \[h\]:mm:sss -* In Export-Excel improved the catch-all handler for insuring values to cope better with nested objects \(\#419\) and reduce the number of parse operations -* Added -Calculate switch to Export-Excel and Close-Excel Package; EPPlus needs formulas to OMIT the leading = sign so where formula is set it now strips a leading = sign -* Added -PivotTotals parameter where there was already -NoTotalsInPivot new one allows None, Both, Rows, Columns. \(\#415\) -* When appending Export-Excel only extended tables and ranges if they were explicitly specified. It now does it automatically. -* Compare and Merge worksheet originally had a problem with > 26 columns, I fixed merge turns out I hadn't fixed compare ... I have now -* Fixed bug where Export-Excel would not recognize it had to set $TitleFillPattern - made the default 'Solid' -* ExcludeProperty in Export-Excel now supports wildcards. -* Added DateTime to the list of types which can be exported as single column. -* Added Password support to Open- and Close-ExcelPackage \(password was not doing anything in Export-Excel\) -* Gave Expand-NumberFormat a better grasp of currency layouts - it follows .NET which is not always the same as Excel would set:-\( - -## What's new in Release 5.1.1 - -* Set-Row and Set-Column will now create hyperlinks and insert dates correctly -* Import-Excel now has an argument completer for Worksheet name - this can be slow on large files -* The NumberFormat parameter \(in Export-Excel, Set-Row, Set-Column, Set-Format and Add-ConditionalFormat\) and X&YAxisNumberFormat parameters \(in New-ExcelChartDefinition and Add-ExcelChart\) now have an argument completer and the names Currency, Number, Percentage, Scientific, Fraction, Short Date ,Short time,Long time, Date-Time and Text will be converted to the correct Excel formatting strings. -* Added new function Select-Worksheet to make a named sheet active: Added -Activate switch to Add-Worksheet, to make current sheet active, Export-Excel and Add-PivotTable support -Activate and pass it to Add-Worksheet, and New-PivotTableDefinition allows it to be part of the Pivot TableDefinition. -* Fixed a bug in Set-Format which caused -Hidden not to work -* Made the same changes to Add-Conditional format as set format so -switch:$false is processed, and 0 enums and values are processed correctly -* In Export-Excel, wrapped calls to Add-CellValue in a try catch so a value which causes an issue doesn't crash the whole export but generates a warning instead \(\#410\) . -* Additional tests. - -## What's new to July 18 - -* Changed parameter evaluation in Set-Format to support -bold:$false \(and other switches so that if false is specified the attribute will be removed \), and to bug were enums with a value of zero, and other zero parameters were not set. -* Moved chart creation into its own function \(Add-Excel chart\) within Export-Excel.ps1. Renamed New-Excelchart to New-ExcelChartDefinition to make it clearer that it is not making anything in the workbook \(but for compatibility put an alias of New-ExcelChart in so existing code does not break\). Found that -Header does nothing, so it isn't Add-Excel chart and there is a message that does nothing in New-ExcelChartDefinition . -* Added -BarChart -ColumnChart -LineChart -PieChart parameters to Export-Excel for quick charts without giving a full chart definition. -* Added parameters for managing chart Axes and legend -* Added some chart tests to Export-Excel.tests.ps1. \(but tests & examples for quick charts , axes or legends still on the to do list \) -* Fixed some bad code which had been checked-in in-error and caused adding charts to break. \(This was not seen outside GitHub \#377\) -* Added "Reverse" parameter to Add-ConditionalFormatting ; and added -PassThru to make it easier to modify details of conditional formatting rules after creation \(\#396\) -* Refactored ConditionalFormatting code in Export excel to use Add-ConditionalFormatting. -* Rewrote Copy-ExcelWorksheet to use copy functionality rather than import \| export \(395\) -* Found sorts could be inconsistent in Merge-MultipleWorksheet, so now sort on more columns. -* Fixed a bug introduced into Compare-Worksheet by the change described in the June changes below, this meant the font color was only being set in one sheet, when a row was changed. Also found that the PowerShell ISE and shell return Compare-Object results in different sequences which broke some tests. Applied a sort to ensure things are in a predictable order. \(\#375\) -* Removed \(2\) calls to Get-ExcelColumnName \(Removed and then restored function itself\) -* Fixed an issue in Export-Excel where formulas were inserted as strings if "NoNumberConversion" is applied \(\#374\), and made sure formatting is applied to formula cells -* Fixed an issue with parameter sets in Export-Excel not being determined correctly in some cases \(I think this had been resolved before and might have regressed\) -* Reverted the \[double\]::tryParse in export excel to the previous \(longer\) way, as the shorter way was not behaving correctly with with the number formats in certain regions. \(also \#374\) -* Changed Table, Range and AutoRangeNames to apply to whole data area if no data has been inserted OR to inserted data only if it has.\(\#376\) This means that if there are multiple inserts only inserted data is touched, rather than going as far down and/or right as the furthest used cell. Added a test for this. -* Added more of the Parameters from Export-Excel to Join-worksheet, join just calls export-excel with these parameters so there is no code behind them \(\#383\) -* Added more of the Parameters from Export-Excel to Send-SQLDataToExcel, send just calls export-excel with these parameters... -* Added support for passing a System.Data.DataTable directly to Send-SQLDataToExcel -* Fixed a bug in Merge-MultipleSheets where if the key was "name", columns like "displayName" would not be processed correctly, nor would names like "something\_ROW". Added tests for Compare, Merge and Join Worksheet -* Add-Worksheet , fixed a regression with move-after \(\#392\), changed way default worksheet name is decided, so if none is specified, and an existing worksheet is copied \(see June additions\) and the name doesn't already exist, the original sheet name will be kept. \(\#393\) If no name is given an a blank sheet is created, then it will be named sheetX where X is the number of the sheet \(so if you have sheets FOO and BAR the new sheet will be Sheet3\). - -## New in June 18 - -* New commands - Diff , Merge and Join - * `Compare-Worksheet` \(introduced in 5.0\) uses the built in `Compare-object` command, to output a command-line DIFF and/or color the worksheet to show differences. For example, if my sheets are Windows services the _extra_ rows or rows where the startup status has changed get highlighted - * `Merge-Worksheet` \(also introduced in 5.0\) joins two lumps, side by highlighting the differences. So now I can have server A's services and Server Bs Services on the same page. I figured out a way to do multiple sheets. So I can have Server A,B,C,D on one page :-\) that is `Merge-MultpleSheets` - - For this release I've fixed heaven only knows how many typos and proof reading errors in the help for these two, the only code change is to fix a bug if two worksheets have different names, are in different files and the Comparison sends the delta in the second back before the one in first, then highlighting changed properties could throw an error. Correcting the spelling of Merge-MultipleSheets is potentially a breaking change \(and it is still plural!\) - - also fixed a bug in compare worksheet where color might not be applied correctly when the worksheets came from different files and had different name. - - * `Join-Worksheet` is **new** for this release. At it's simplest it copies all the data in Worksheet A to the end of Worksheet B -* Add-Worksheet - * I have moved this from ImportExcel.psm1 to ExportExcel.ps1 and it now can move a new worksheet to the right place, and can copy an existing worksheet \(from the same or a different workbook\) to a new one, and I set the Set return-type to aid intellisense -* New-PivotTableDefinition - * Now Supports `-PivotFilter` and `-PivotDataToColumn`, `-ChartHeight/width` `-ChartRow/Column`, `-ChartRow/ColumnPixelOffset` parameters -* Set-Format - * Fixed a bug where the `-address` parameter had to be named, although the examples in `export-excel` help showed it working by position \(which works now. \) -* Export-Excel - * I've done some re-factoring - 1. I "flattened out" small "called-once" functions , add-title, convert-toNumber and Stop-ExcelProcess. - 2. It now uses Add-Worksheet, Open-ExcelPackage and Add-ConditionalFormat instead of duplicating their functionality. - 3. I've moved the PivotTable functionality \(which was doubled up\) out to a new function "Add-PivotTable" which supports some extra parameters PivotFilter and PivotDataToColumn, ChartHeight/width ChartRow/Column, ChartRow/ColumnPixelOffsets. - 4. I've made the try{} catch{} blocks cover smaller blocks of code to give a better idea where a failure happened, some of these now Warn instead of throwing - I'd rather save the data with warnings than throw it away because we can't add a chart. Along with this I've added some extra write-verbose messages - * Bad column-names specified for Pivots now generate warnings instead of throwing. - * Fixed issues when pivot tables / charts already exist and an export tries to create them again. - * Fixed issue where AutoNamedRange, NamedRange, and TableName do not work when appending to a sheet which already contains the range\(s\) / table - * Fixed issue where AutoNamedRange may try to create ranges with an illegal name. - * Added check for illegal characters in RangeName or Table Name \(replace them with "\_"\), changed tablename validation to allow spaces and applied same validation to RangeName - * Fixed a bug where BoldTopRow is always bolds row 1 even if the export is told to start at a lower row. - * Fixed a bug where titles throw pivot table creation out of alignment. - * Fixed a bug where Append can overwrite the last rows of data if the initial export had blank rows at the top of the sheet. - * Removed the need to specify a fill type when specifying a title background color - * Added MoveToStart, MoveToEnd, MoveBefore and MoveAfter Parameters - these go straight through to Add worksheet - * Added "NoScriptOrAliasProperties" "DisplayPropertySet" switches \(names subject to change\) - combined with ExcludeProperty these are a quick way to reduce the data exported \(and speed things up\) - * Added PivotTableName Switch \(in line with 5.0.1 release\) - * Add-CellValue now understands URI item properties. If a property is of type URI it is created as a hyperlink to speed up Add-CellValue - * Commented out the write verbose statements even if verbose is silenced they cause a significant performance impact and if it's on they will cause a flood of messages. - * Re-ordered the choices in the switch and added an option to say "If it is numeric already post it as is" - * Added an option to only set the number format if doesn't match the default for the sheet. -* Export-Excel Pester Tests - * I have converted examples 1-9, 11 and 13 from Export-Excel help into tests and have added some additional tests, and extra parameters to the example command to get better test coverage. The test so far has 184 "should" conditions grouped as 58 "IT" statements; but is still a work in progress. -* Compare-Worksheet pester tests -* [James O'Neill](https://twitter.com/jamesoneill) added `Compare-Worksheet` - * Compares two worksheets with the same name in different files. - -**4/22/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 -* [Nasir Zubair](https://github.com/nzubair) added `ConvertEmptyStringsToNull` to the function `ConvertFrom-ExcelToSQLInsert` - * If specified, cells without any data are replaced with NULL, instead of an empty string. This is to address behaviors in certain DBMS where an empty string is insert as 0 for INT column, instead of a NULL value. - -**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, bottom, left and right - * Added parameters to set `value` and `formula` - -```text -$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 +## Create a spreadsheet +Here is a quick example that will create spreadsheet file from CSV data. Works with JSON, Databases, and more. + +```powershell +$data = ConvertFrom-Csv @" +Region,State,Units,Price +West,Texas,927,923.71 +North,Tennessee,466,770.67 +East,Florida,520,458.68 +East,Maine,828,661.24 +West,Virginia,465,053.58 +North,Missouri,436,235.67 +South,Kansas,214,992.47 +North,North Dakota,789,640.72 +South,Delaware,712,508.55 "@ + +$data | Export-Excel .\salesData.xlsx ``` -![](https://github.com/dfinke/ImportExcel/blob/master/images/CustomReport.png?raw=true) +![](images/salesdata.png) -* Added `-PivotFilter` parameter, allows you to set up a filter so you can drill down into a subset of the overall dataset. +## Read a spreadsheet -```text -$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 +Quickly read a spreadsheet document into a PowerShell array. + +```powershell +$data = Import-Excel .\salesData.xlsx +``` + +```powershell +Region State Units Price +------ ----- ----- ----- +West Texas 927 923.71 +North Tennessee 466 770.67 +East Florida 520 458.68 +East Maine 828 661.24 +West Virginia 465 053.58 +North Missouri 436 235.67 +South Kansas 214 992.47 +North North Dakota 789 640.72 +South Delaware 712 508.55 +``` + +## Add a chart to spreadsheet + +Chart generation is as easy as 123. Building charts based on data in your worksheet doesn't get any easier. + +Plus, it is automated and repeatable. + +```powershell +$data = ConvertFrom-Csv @" +Region,State,Units,Price +West,Texas,927,923.71 +North,Tennessee,466,770.67 +East,Florida,520,458.68 +East,Maine,828,661.24 +West,Virginia,465,053.58 +North,Missouri,436,235.67 +South,Kansas,214,992.47 +North,North Dakota,789,640.72 +South,Delaware,712,508.55 "@ + +$chart = New-ExcelChartDefinition -XRange State -YRange Units -Title "Units by State" -NoLegend + +$data | Export-Excel .\salesData.xlsx -AutoNameRange -ExcelChartDefinition $chart -Show ``` -![](https://github.com/dfinke/ImportExcel/blob/master/images/PivotTableFilter.png?raw=true) +![](images/salesDataChart.png) -**3/14/2018** +## Add a pivot table to spreadsheet -* 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` **$false** and **$BorderRound** +Categorize, sort, filter, and summarize any amount data with pivot tables. Then add charts. - **1/1/2018** +```powershell +$data = ConvertFrom-Csv @" +Region,State,Units,Price +West,Texas,927,923.71 +North,Tennessee,466,770.67 +East,Florida,520,458.68 +East,Maine,828,661.24 +West,Virginia,465,053.58 +North,Missouri,436,235.67 +South,Kansas,214,992.47 +North,North Dakota,789,640.72 +South,Delaware,712,508.55 +"@ -* 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. - -```text - get-process | where Company | select Company, Handles, WorkingSet | - export-excel C:\temp\testColumnGrand.xlsx ` - -Show -ClearSheet -KillExcel ` - -IncludePivotTable -PivotRows Company -PivotData @{"Handles"="average"} -NoTotalsInPivot +$data | Export-Excel .\salesData.xlsx -AutoNameRange -Show -PivotRows Region -PivotData @{'Units'='sum'} -PivotChartType PieExploded3D ``` -* 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 +![](images/SalesDataChartPivotTable.png) -**11/23/2017** +# Bonus Points -More great additions and thanks to [James O'Neill](https://twitter.com/jamesoneill) +## Create a separate CSV file for each Excel sheet -* 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. +Do you have a Excel file with multiple sheets and you need to convert each sheet to CSV file? -**10/30/2017** +### Problem Solved -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. +The `yearlyRetailSales.xlsx` has 12 sheets of retail data for the year. -\(Check out the examples `help Export-Excel -Examples`\) - -* New parameter `Package` allows an ExcelPackage object returned by `-passThru` to be passed in -* New parameter `ExcludeProperty` to remove unwanted properties without needing to go through `select-object` -* New parameter `Append` code to read the existing headers and move the insertion point below the current data -* New parameter `ClearSheet` which removes the worksheet and any past data -* Remove any existing Pivot table before trying to \[re\]create it -* Check for inserting a pivot table so if `-InsertPivotChart` is specified it implies `-InsertPivotTable` - -\(Check out the examples `help Export-Excel -Examples`\) - -* New function `Export-Charts` \(requires Excel to be installed\) - Export Excel charts out as JPG files -* New function `Add-ConditionalFormatting` Adds conditional formatting to worksheet -* New function `Set-Format` Applies Number, font, alignment and color formatting to a range of Excel Cells -* `ColorCompletion` an argument completer for `Colors` for params across functions - -I also worked out the parameters so you can do this, which is the same as passing `-Now`. It creates an Excel file name for you, does an auto fit and sets up filters. - -`ps | select Company, Handles | Export-Excel` - -**10/13/2017** - -Added `New-PivotTableDefinition`. You can create and wire up a PivotTable to a WorkSheet. You can also create as many PivotTable Worksheets to point a one Worksheet. Or, you create many Worksheets and many corresponding PivotTable Worksheets. - -Here you can create a WorkSheet with the data from `Get-Service`. Then create four PivotTables, pointing to the data each pivoting on a different dimension and showing a different chart - -```text -$base = @{ - SourceWorkSheet = 'gsv' - PivotData = @{'Status' = 'count'} - IncludePivotChart = $true -} - -$ptd = [ordered]@{} - -$ptd += New-PivotTableDefinition @base servicetype -PivotRows servicetype -ChartType Area3D -$ptd += New-PivotTableDefinition @base status -PivotRows status -ChartType PieExploded3D -$ptd += New-PivotTableDefinition @base starttype -PivotRows starttype -ChartType BarClustered3D -$ptd += New-PivotTableDefinition @base canstop -PivotRows canstop -ChartType ConeColStacked - -Get-Service | Export-Excel -path $file -WorkSheetname gsv -Show -PivotTableDefinition $ptd -``` - -**10/4/2017** - -Thanks to [https://github.com/ili101](https://github.com/ili101) : - -* Fix Bug, Unable to find type \[PSPlot\] -* Fix Bug, AutoFilter with TableName create corrupted Excel file. - -**10/2/2017** - -Thanks to [Jeremy Brun](https://github.com/jeremytbrun) Fixed issues related to use of -Title parameter combined with column formatting parameters. - -* [Issue \#182](https://github.com/dfinke/ImportExcel/issues/182) -* [Issue \#89](https://github.com/dfinke/ImportExcel/issues/89) - -**9/28/2017 \(Version 4.0.1\)** - -* Added a new parameter called `Password` to import password protected files -* Added even more `Pester` tests for a more robust and bug free module -* Renamed parameter 'TopRow' to 'StartRow' - - This allows us to be more concise when new parameters \('StartColumn', ..\) will be added in the future Your code will not break after the update, because we added an alias for backward compatibility - -Special thanks to [robinmalik](https://github.com/robinmalik) for providing us with [the code](https://github.com/dfinke/ImportExcel/issues/174) to implement this new feature. A high five to [DarkLite1](https://github.com/DarkLite1) for the implementation. - -**9/12/2017 \(Version 4.0.0\)** - -Super thanks and hat tip to [DarkLite1](https://github.com/DarkLite1). There is now a new and improved `Import-Excel`, not only in functionality, but also improved readability, examples and more. Not only that, he's been running it in production in his company for a number of weeks! - -_Added_ `Update-FirstObjectProperties` Updates the first object to contain all the properties of the object with the most properties in the array. Check out the help. - -_**Breaking Changes**_: Due to a big portion of the code that is rewritten some slightly different behavior can be expected from the `Import-Excel` function. This is especially true for importing empty Excel files with or without using the `TopRow` parameter. To make sure that your code is still valid, please check the examples in the help or the accompanying `Pester` test file. - -Moving forward, we are planning to include automatic testing with the help of `Pester`, `Appveyor` and `Travis`. From now on any changes in the module will have to be accompanied by the corresponding `Pester` tests to avoid breakages of code and functionality. This is in preparation for new features coming down the road. - -**7/3/2017** - -Thanks to [Mikkel Nordberg](https://www.linkedin.com/in/mikkelnordberg). He contributed a `ConvertTo-ExcelXlsx`. To use it, Excel needs to be installed. The function converts the older Excel file format ending in `.xls` to the new format ending in `.xlsx`. - -**6/15/2017** - -Huge thank you to [DarkLite1](https://github.com/DarkLite1)! Refactoring of code, adding help, adding features, fixing bugs. Specifically this long outstanding one: - -[Export-Excel: Numeric values not correct](https://github.com/dfinke/ImportExcel/issues/168) - -It is fantastic to work with people like `DarkLite1` in the community, to help make the module so much better. A hat to you. - -Another shout out to [Damian Reeves](https://twitter.com/DamReev)! His questions turn into great features. He asked if it was possible to import an Excel worksheet and transform the data into SQL `INSERT` statements. We can now answer that question with a big YES! - -```text -ConvertFrom-ExcelToSQLInsert People .\testSQLGen.xlsx -``` - -```text -INSERT INTO People ('First', 'Last', 'The Zip') Values('John', 'Doe', '12345'); -INSERT INTO People ('First', 'Last', 'The Zip') Values('Jim', 'Doe', '12345'); -INSERT INTO People ('First', 'Last', 'The Zip') Values('Tom', 'Doe', '12345'); -INSERT INTO People ('First', 'Last', 'The Zip') Values('Harry', 'Doe', '12345'); -INSERT INTO People ('First', 'Last', 'The Zip') Values('Jane', 'Doe', '12345'); -``` - -### Bonus Points - -Use the underlying `ConvertFrom-ExcelData` function and you can use a scriptblock to format the data however you want. - -```text -ConvertFrom-ExcelData .\testSQLGen.xlsx { - param($propertyNames, $record) - - $reportRecord = @() - foreach ($pn in $propertyNames) { - $reportRecord += "{0}: {1}" -f $pn, $record.$pn - } - $reportRecord +="" - $reportRecord -join "`r`n" -} -``` - -Generates - -```text -First: John -Last: Doe -The Zip: 12345 - -First: Jim -Last: Doe -The Zip: 12345 - -First: Tom -Last: Doe -The Zip: 12345 - -First: Harry -Last: Doe -The Zip: 12345 - -First: Jane -Last: Doe -The Zip: 12345 -``` - -**2/2/2017** - -Thank you to [DarkLite1](https://github.com/DarkLite1) for more updates - -* TableName with parameter validation, throws an error when the TableName: - * Starts with something else then a letter - * Is NULL or empty - * Contains spaces -* Numeric parsing now uses `CurrentInfo` to use the system settings - -**2/14/2017** - -Big thanks to [DarkLite1](https://github.com/DarkLite1) for some great updates - -* `-DataOnly` switch added to `Import-Excel`. When used it will only generate objects for rows that contain text values, not for empty rows or columns. -* `Get-ExcelWorkBookInfo` - retrieves information of an Excel workbook. - - ```text - Get-ExcelWorkbookInfo .\Test.xlsx - - CorePropertiesXml : #document - Title : - Subject : - Author : Konica Minolta User - Comments : - Keywords : - LastModifiedBy : Bond, James (London) GBR - LastPrinted : 2017-01-21T12:36:11Z - Created : 17/01/2017 13:51:32 - Category : - Status : - ExtendedPropertiesXml : #document - Application : Microsoft Excel - HyperlinkBase : - AppVersion : 14.0300 - Company : Secret Service - Manager : - Modified : 10/02/2017 12:45:37 - CustomPropertiesXml : #document - ``` - -**12/22/2016** - -* Added `-Now` switch. This short cuts the process, automatically creating a temp file and enables the `-Show`, `-AutoFilter`, `-AutoSize` switches. - -```text -Get-Process | Select Company, Handles | Export-Excel -Now -``` - -* Added ScriptBlocks for coloring cells. Check out [Examples](https://github.com/dfinke/ImportExcel/tree/master/Examples/FormatCellStyles) - -```text -Get-Process | - Select-Object Company,Handles,PM, NPM| - Export-Excel $xlfile -Show -AutoSize -CellStyleSB { - param( - $workSheet, - $totalRows, - $lastColumn - ) - - Set-CellStyle $workSheet 1 $LastColumn Solid Cyan - - foreach($row in (2..$totalRows | Where-Object {$_ % 2 -eq 0})) { - Set-CellStyle $workSheet $row $LastColumn Solid Gray - } - - foreach($row in (2..$totalRows | Where-Object {$_ % 2 -eq 1})) { - Set-CellStyle $workSheet $row $LastColumn Solid LightGray - } - } -``` - -![](https://github.com/dfinke/ImportExcel/blob/master/images/CellFormatting.png?raw=true) - -**9/28/2016** - -[Fixed](https://github.com/dfinke/ImportExcel/pull/126) PowerShell 3.0 compatibility. Thanks to [headsphere](https://github.com/headsphere). He used `$obj.PSObject.Methods[$target]` syntax to make it backward compatible. PS v4.0 and later allow `$obj.$target`. - -Thank you to [xelsirko](https://github.com/xelsirko) for fixing - _Import-module importexcel gives version warning if started inside background job_ - -**8/12/2016** - -[Fixed](https://github.com/dfinke/ImportExcel/issues/115) reading the headers from cells, moved from using `Text` property to `Value` property. - -**7/30/2016** - -* Added `Copy-ExcelWorksheet`. Let's you copy a work sheet from one Excel workbook to another. - -**7/21/2016** - -* Fixes `Import-Excel` \#68 - -**7/7/2016** - -[Attila Mihalicz](https://github.com/attilamihalicz) fixed two issues - -* Removing extra spaces after the backtick -* Uninitialized variable $idx leaks into the pipeline when `-TableName` parameter is used - -Thanks Attila. - -**7/1/2016** - -* Pushed 2.2.7 fixed resolve path in Get-ExcelSheetInfo -* Fixed [Casting Error in Export-Excel](https://github.com/dfinke/ImportExcel/issues/108) -* For `Import-Excel` change Resolve-Path to return ProviderPath for use with UNC - -**6/01/2016** - -* Added -UseDefaultCredentials to both `Import-Html` and `Get-HtmlTable` -* New functions, `Import-UPS` and `Import-USPS`. Pass in a valid tracking \# and it scrapes the page for the delivery details - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/Tracking.gif) - -**4/30/2016** - -Huge thank you to [Willie Möller](https://github.com/W1M0R) - -* He added a version check so the PowerShell Classes don't cause issues for down-level version of PowerShell -* He also contributed the first Pester tests for the module. Super! Check them out, they'll be the way tests will be implemented going forward - -**4/18/2016** - -Thanks to [Paul Williams](https://github.com/pauldalewilliams) for this feature. Now data can be transposed to columns for better charting. - -```text -$file = "C:\Temp\ps.xlsx" -rm $file -ErrorAction Ignore - -ps | - where company | - select Company,PagedMemorySize,PeakPagedMemorySize | - Export-Excel $file -Show -AutoSize ` - -IncludePivotTable ` - -IncludePivotChart ` - -ChartType ColumnClustered ` - -PivotRows Company ` - -PivotData @{PagedMemorySize='sum';PeakPagedMemorySize='sum'} -``` - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PivotAsRows.png) - -Add `-PivotDataToColumn` - -```text -$file = "C:\Temp\ps.xlsx" -rm $file -ErrorAction Ignore - -ps | - where company | - select Company,PagedMemorySize,PeakPagedMemorySize | - Export-Excel $file -Show -AutoSize ` - -IncludePivotTable ` - -IncludePivotChart ` - -ChartType ColumnClustered ` - -PivotRows Company ` - -PivotData @{PagedMemorySize='sum';PeakPagedMemorySize='sum'} ` - -PivotDataToColumn -``` - -And here is the new chart view ![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PivotAsColumns.png) - -**4/7/2016** - -Made more methods fluent - -```text -$t=Get-Range 0 5 .2 - -$t2=$t|%{$_*$_} -$t3=$t|%{$_*$_*$_} - -(New-Plot). - Plot($t,$t, $t,$t2, $t,$t3). - SetChartPosition("i"). - SetChartSize(500,500). - Title("Hello World"). - Show() -``` - -**3/31/2016** - -* Thanks to [redoz](https://github.com/redoz) Multi Series Charts are now working - -Also check out how you can create a table and then with Excel notation, index into the data for charting `"Impressions[A]"` - -```text -$data = @" -A,B,C,Date -2,1,1,2016-03-29 -5,10,1,2016-03-29 -"@ | ConvertFrom-Csv - -$c = New-ExcelChart -Title Impressions ` - -ChartType Line -Header "Something" ` - -XRange "Impressions[Date]" ` - -YRange @("Impressions[B]","Impressions[A]") - -$data | - Export-Excel temp.xlsx -AutoSize -TableName Impressions -Show -ExcelChartDefinition $c -``` - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/MultiSeries.gif) - -**3/26/2016** - -* Added `NumberFormat` parameter - -```text -$data | - Export-Excel -Path $file -Show -NumberFormat '[Blue]$#,##0.00;[Red]-$#,##0.00' -``` - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/Formatting.png) - -**3/18/2016** - -* Added `Get-Range`, `New-Plot` and Plot Cos example -* Updated EPPlus DLL. Allows markers to be changed and colored -* Handles and warns if auto name range names are also valid Excel ranges - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PSPlot.gif) - -**3/7/2016** - -* Added `Header` and `FirstDataRow` for `Import-Html` - -**3/2/2016** - -* Added `GreaterThan`, `GreaterThanOrEqual`, `LessThan`, `LessThanOrEqual` to `New-ConditionalText` - -```text -echo 489 668 299 777 860 151 119 497 234 788 | - Export-Excel c:\temp\test.xlsx -Show ` - -ConditionalText (New-ConditionalText -ConditionalType GreaterThan 525) -``` - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/GTConditional.png) - -**2/22/2016** - -* `Import-Html` using Lee Holmes [Extracting Tables from PowerShell’s Invoke-WebRequest](http://www.leeholmes.com/blog/2015/01/05/extracting-tables-from-PowerShells-invoke-webrequest/) - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/ImportHtml.gif) - -**2/17/2016** - -* Added Conditional Text types of `Equal` and `NotEqual` -* Phone \#'s like '+33 011 234 34' will be now be handled correctly - -### Try _PassThru_ - -```text -$file = "C:\Temp\passthru.xlsx" -rm $file -ErrorAction Ignore - -$xlPkg = $( - New-PSItem north 10 - New-PSItem east 20 - New-PSItem west 30 - New-PSItem south 40 -) | Export-Excel $file -PassThru - -$ws=$xlPkg.Workbook.Worksheets[1] - -$ws.Cells["A3"].Value = "Hello World" -$ws.Cells["B3"].Value = "Updating cells" -$ws.Cells["D1:D5"].Value = "Data" - -$ws.Cells.AutoFitColumns() - -$xlPkg.Save() -$xlPkg.Dispose() - -Invoke-Item $file -``` - -### Result - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PassThru.png) - -**1/18/2016** - -* Added `Conditional Text Formatting`. [Boe Prox](https://twitter.com/proxb) posted about [HTML Reporting, Part 2: Take Your Reporting a Step Further](https://mcpmag.com/articles/2016/01/14/html-reporting-part-2.aspx) and colorized cells. Great idea, now part of the PowerShell Excel module. - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/ConditionalText2.gif) - -**1/7/2016** - -* Added `Get-ExcelSheetInfo` - Great contribution from _Johan Åkerström_ check him out on [GitHub](https://github.com/CosmosKey) and [Twitter](https://twitter.com/neptune443) - -![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/GetExcelSheetInfo.png) - -**12/26/2015** - -* Added `NoLegend`, `Show-Category`, `ShowPercent` for all charts including Pivot Charts -* Updated PieChart, BarChart, ColumnChart and Line chart to work with the pipeline and added `NoLegend`, `Show-Category`, `ShowPercent` - -**12/17/2015** - -These new features open the door for really sophisticated work sheet creation. - -Stay tuned for a [blog post](http://www.dougfinke.com/blog/) and examples. - -_**Quick List**_ - -* StartRow, StartColumn for placing data anywhere in a sheet -* New-ExcelChart - Add charts to a sheet, multiple series for a chart, locate the chart anywhere on the sheet -* AutoNameRange, Use functions and/or calculations in a cell -* Quick charting using PieChart, BarChart, ColumnChart and more - -![](https://raw.githubusercontent.com/dfinke/GifCam/master/JustCharts.gif) - -**10/20/2015** - -Big bug fix for version 3.0 PowerShell folks! - -This technique fails in 3.0 and works in 4.0 and later. - -```text -$m="substring" -"hello".$m(2,1) -``` - -Adding `.invoke` works in 3.0 and later. - -```text -$m="substring" -"hello".$m.invoke(2,1) -``` - -A _**big thank you**_ to [DarkLite1](https://github.com/DarkLite1) for adding the help to Export-Excel. - -Added `-HeaderRow` parameter. Sometimes the heading does not start in Row 1. - -**10/16/2015** - -Fixes [Export-Excel generates corrupt Excel file](https://github.com/dfinke/ImportExcel/issues/46) - -**10/15/2015** - -`Import-Excel` has a new parameter `NoHeader`. If data in the sheet does not have headers and you don't want to supply your own, `Import-Excel` will generate the property name. - -`Import-Excel` now returns `.Value` rather than `.Text` - -**10/1/2015** - -Merged ValidateSet for Encoding and Extension. Thank you [Irwin Strachan](https://github.com/irwins). - -**9/30/2015** - -Export-Excel can now handle data that is **not** an object - -```text -echo a b c 1 $true 2.1 1/1/2015 | Export-Excel c:\temp\test.xlsx -Show -``` - -Or - -```text -dir -Name | Export-Excel c:\temp\test.xlsx -Show -``` - -**9/25/2015** - -**Hide worksheets** Got a great request from [forensicsguy20012004](https://github.com/forensicsguy20012004) to hide worksheets. You create a few pivotables, generate charts and then pivot table worksheets don't need to be visible. - -`Export-Excel` now has a `-HideSheet` parameter that takes and array of worksheet names and hides them. - -**Example** - -Here, you create four worksheets named `PM`,`Handles`,`Services` and `Files`. - -The last line creates the `Files` sheet and then hides the `Handles`,`Services` sheets. - -```text -$p = Get-Process - -$p|select company, pm | Export-Excel $xlFile -WorkSheetname PM -$p|select company, handles| Export-Excel $xlFile -WorkSheetname Handles -Get-Service| Export-Excel $xlFile -WorkSheetname Services - -dir -File | Export-Excel $xlFile -WorkSheetname Files -Show -HideSheet Handles, Services -``` - -**Note** There is a bug in EPPlus that does not let you hide the first worksheet created. Hopefully it'll resolved soon. - -**9/11/2015** - -Added Conditional formatting. See [TryConditional.ps1](https://github.com/dfinke/ImportExcel/blob/master/TryConditional.ps1) as an example. - -Or, check out the short _**"How To"**_ video. - -[![image](http://www.dougfinke.com/videos/excelpsmodule/ExcelPSModule_First_Frame.png)](http://www.dougfinke.com/videos/excelpsmodule/excelpsmodule.mp4) - -**8/21/2015** - -* Now import Excel sheets even if the file is open in Excel. Thank you [Francois Lachance-Guillemette](https://github.com/francoislg) - -**7/09/2015** - -* For -PivotRows you can pass a `hashtable` with the name of the property and the type of calculation. `Sum`, `Average`, `Max`, `Min`, `Product`, `StdDev`, `StdDevp`, `Var`, `Varp` - -```text -Get-Service | - Export-Excel "c:\temp\test.xlsx" ` - -Show ` - -IncludePivotTable ` - -PivotRows status ` - -PivotData @{status='count'} -``` - -**6/16/2015 \(Thanks Justin\)** - -* Improvements to PivotTable overwriting -* Added two parameters to Export-Excel - * RangeName - Turns the data piped to Export-Excel into a named range. - * TableName - Turns the data piped to Export-Excel into an excel table. - -Examples - -```text -Get-Process|Export-Excel foo.xlsx -Verbose -IncludePivotTable -TableName "Processes" -Show -Get-Process|Export-Excel foo.xlsx -Verbose -IncludePivotTable -RangeName "Processes" -Show -``` - -**5/25/2015** - -* Fixed null header problem - -**5/17/2015** - -* Added three parameters: - * FreezeTopRow - Freezes the first row of the data - * AutoFilter - Enables filtering for the data in the sheet - * BoldTopRow - Bolds the top row of data, the column headers - -Example - -```text -Get-CimInstance win32_service | - select state, accept*, start*, caption | - Export-Excel test.xlsx -Show -BoldTopRow -AutoFilter -FreezeTopRow -AutoSize -``` - -![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/FilterFreezeBold.gif) - -**5/4/2015** - -* Published to PowerShell Gallery. In PowerShell v5 use `Find-Module importexcel` then `Find-Module importexcel | Install-Module` - -**4/27/2015** - -* datetime properties were displaying as ints, now are formatted - -**4/25/2015** - -* Now you can create multiple Pivot tables in one pass - * Thanks to [pscookiemonster](https://twitter.com/pscookiemonster), he submitted a repro case to the EPPlus CodePlex project and got it fixed - -**Example** - -```text -$ps = ps - -$ps | - Export-Excel .\testExport.xlsx -WorkSheetname memory ` - -IncludePivotTable -PivotRows Company -PivotData PM ` - -IncludePivotChart -ChartType PieExploded3D -$ps | - Export-Excel .\testExport.xlsx -WorkSheetname handles ` - -IncludePivotTable -PivotRows Company -PivotData Handles ` - -IncludePivotChart -ChartType PieExploded3D -Show -``` - -![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/MultiplePivotTables.png) - -**4/20/2015** - -* Included and embellished [Claus Nielsen](https://github.com/Claustn) function to take all sheets in an Excel file workbook and create a text file for each `ConvertFrom-ExcelSheet` -* Renamed `Export-MultipleExcelSheets` to `ConvertFrom-ExcelSheet` - -**4/13/2015** - -* You can add a title to the Excel "Report" `Title`, `TitleFillPattern`, `TitleBold`, `TitleSize`, `TitleBackgroundColor` - * Thanks to [Irwin Strachan](http://pshirwin.wordpress.com) for this and other great suggestions, testing and more - -**4/10/2015** - -* Renamed `AutoFitColumns` to `AutoSize` -* Implemented `Export-MultipleExcelSheets` -* Implemented `-Password` for a worksheet -* Replaced `-Force` switch with `-NoClobber` switch -* Added examples for `Get-Help` -* If Pivot table is requested, that sheet becomes the tab selected - -**4/8/2015** - -* Implemented exporting data to **named sheets** via the -WorkSheetname parameter. - -Examples - `gsv | Export-Excel .\test.xlsx -WorkSheetname Services` - -`dir -file | Export-Excel .\test.xlsx -WorkSheetname Files` - -`ps | Export-Excel .\test.xlsx -WorkSheetname Processes -IncludePivotTable -Show -PivotRows Company -PivotData PM` - -**Convert \(All or Some\) Excel Sheets to Text files** - -Reads each sheet in TestSheets.xlsx and outputs it to the data directory as the sheet name with the extension .txt - -```text -ConvertFrom-ExcelSheet .\TestSheets.xlsx .\data -``` - -Reads and outputs sheets like Sheet10 and Sheet20 form TestSheets.xlsx and outputs it to the data directory as the sheet name with the extension .txt - -```text -ConvertFrom-ExcelSheet .\TestSheets.xlsx .\data sheet?0 -``` - -**Example Adding a Title** - -You can set the pattern, size and of if the title is bold. - -```text -$p=@{ - Title = "Process Report as of $(Get-Date)" - TitleFillPattern = "LightTrellis" - TitleSize = 18 - TitleBold = $true - - Path = "$pwd\testExport.xlsx" - Show = $true - AutoSize = $true -} - -Get-Process | - Where Company | Select Company, PM | - Export-Excel @p -``` - -![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/Title.png) - -**Example Export-MultipleExcelSheets** - -![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/ExportMultiple.gif) - -```text -$p = Get-Process - -$DataToGather = @{ - PM = {$p|select company, pm} - Handles = {$p|select company, handles} - Services = {gsv} - Files = {dir -File} - Albums = {(Invoke-RestMethod http://www.dougfinke.com/PowerShellfordevelopers/albums.js)} -} - -Export-MultipleExcelSheets -Show -AutoSize .\testExport.xlsx $DataToGather -``` - -_**NOTE**_ If the sheet exists when using _-WorkSheetname_ parameter, it will be deleted and then added with the new data. - -### Get-Process Exported to Excel - -#### Total Physical Memory Grouped By Company - -![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PivotTablesAndCharts.png) - -### Importing data from an Excel spreadsheet - -![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/TryImportExcel.gif) - -You can also find EPPLus on [Nuget](https://www.nuget.org/packages/EPPlus/). - -### Known Issues - -* Using `-IncludePivotTable`, if that pivot table name exists, you'll get an error. - * Investigating a solution - * _Workaround_ delete the Excel file first, then do the export +This single line of PowerShell converts any number of sheets in an Excel workbook to a separate CSV file. +```powershell +(Import-Excel .\yearlyRetailSales.xlsx *).GetEnumerator() | +ForEach-Object { $_.Value | Export-Csv ($_.key + '.csv') } +``` \ No newline at end of file diff --git a/images/SalesData.png b/images/SalesData.png new file mode 100644 index 0000000000000000000000000000000000000000..e85d158243c6eabf47eafc2e6e6c9103bb6b3433 GIT binary patch literal 10594 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
JKYPrVY zC~~YfJAX#Z7|ZZ=U87NtD#QZ`cNc6%Mk{?}G2AUmky*v>b-e))2X%X%|K;AunaTNX z9^*%+D*qEuRL&<{%vE2ek*BbL0vM73(|Y-&>#SzOa%|VaO0F^axH{BQ0a#SkGqO(-(pX`W&3=%GdzawcfX$JWdYIi1miEg^51GrB$;_8SX@%ZJ@YgcjflF;P(xb z``vCnp4M`(3yqS}l$p}78@*Q1HwQdNO0_MQIv%}vzV28x(SNi6nZ9lHlSmioNu}lA zZw>17MxuIB_ZOrvPB-l08Q)1OQ))klb#J#1Pm4T1^+U^a7l7|G<$TA)z4%>E!G-TT z95)O7szC4X!A6IDtwp`;b8yXj$MwQkJmx!?l7hG&j^OgZ!p>8vZeu&3ZJaqV^Q*!_y87UXgK5*YGg(OEEv#ks9k+5g{CrDBT%z^y}aTz0i2gl z@;}jLGs}HO6ASP0%gjlZ}Dlx5woi;?&S(=6bWr_6FS7}$R~FtgttQ8UYn>s zCHvfBMcA$vDQ22KpbzN{jO}8HFZ#*dwxB#^GF;h~!AU3d@%e-rg1a9BP!Nk4m)EMk z$+}Em&FsZUFqHDpB=AcW9y={VoXld#w(cc;fE2)=zqC`x{k{~Z@9MJb2SVeO612l{ zB1>$}^&G*Gczr8w-CT;yvoZRAV}K#x{rJRMklNW)NH8Yho0-xzP*K zfA8>}#)s(u+a^RKa!;in3^QW<-CN4gd&pOn=euLNfMzpJe;sJn!hUr2AZ&0>4Ckp%z1hBWR~R0ii9a0{wLqj!yk zX#Uz^rVi}x43}+{J~h5uJ@|Dcm}@ooHBY@a6sx%vxd)*^3g#c`ijh+@u|_nWG1dL_ zd-Gyh6!nQlWakH7!G3P1>fPQ;g2syUkHn=*y&eWg>QI`e;}|@a{));r^+}nXgi)SPb2izcjs4K0~P92QL>?dty!6HOIiO z3e1e^Z4wMWN)xk#pEdzs}Y%BAG!Xv#(h<37}qX5}tN$l=PJ-?K{A zS>Qf3eBAl#RtVK4Rua}!PFZ{_+GMCbnzFi6s+&h3g3C~q@|5&wM2|zSpHT)qah_*^ zypz~;4tUqvlA5R5Y`V>;3l@pO+Y^9L?+`0&Iu?H<>)01&6viTHbhcAMM8Ri}>k@0Z zp1Khq`i=9ng�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�O8L5lF50l19zlAgu5SyFI!#pdj( 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 aY=WdDWA;gc_$t7WmW78!?yG?w&;1tzf2e~1 literal 0 HcmV?d00001 diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ad6779c6964e0c224ed06213141bc378ceaeb78f GIT binary patch literal 22972 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 literal 0 HcmV?d00001 From 267d15f99aa4ecf4e099569b163683efc679c4b4 Mon Sep 17 00:00:00 2001 From: dfinke Date: Thu, 5 May 2022 18:21:27 -0400 Subject: [PATCH 122/140] Add videos and articles --- README.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7c5f48..dee9e11 100644 --- a/README.md +++ b/README.md @@ -117,9 +117,35 @@ Do you have a Excel file with multiple sheets and you need to convert each sheet The `yearlyRetailSales.xlsx` has 12 sheets of retail data for the year. -This single line of PowerShell converts any number of sheets in an Excel workbook to a separate CSV file. +This single line of PowerShell converts any number of sheets in an Excel workbook to separate CSV files. ```powershell (Import-Excel .\yearlyRetailSales.xlsx *).GetEnumerator() | ForEach-Object { $_.Value | Export-Csv ($_.key + '.csv') } -``` \ No newline at end of file +``` + +# Getting Started + +## Videos + +- [Export-Excel Hello World](https://youtu.be/fvKKdIzJCws?list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq) +- [Make Excel Data Pop](https://youtu.be/gQaYI5hxqM4?list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq) +- [Slice And Dice Data](https://youtu.be/kzllxvqr3TY?list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq) +- [Lightning talk - PowerShell Excel Module](https://youtu.be/znVu2q11Rp4?list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq) + +## More Videos + +- [Look smarter: deliver your work in Excel](https://youtu.be/tu8Mfkwi8zI) - James O'Neill +- [Module Monday: ImportExcel](https://youtu.be/rBA_IeTmCb8?t=5) - Adam Driscoll +- [Tutorials Excel Module Part 1](https://youtu.be/2cwBuYbZ3To) +- [Tutorials Excel Module Part 2](https://youtu.be/8ojg-qjOnVI) +- [Tutorials Excel Module Part 3](https://youtu.be/3IgASPD0UrQ) +- [PowerShell Excel - Invoke-ExcelQuery](https://youtu.be/_7xuhsZm0Ao) +- [Powershell Excel - Data Validation](https://youtu.be/NGhahuY8j1M) +- [Creating Dashboards xPlatform](https://youtu.be/qMWkZt6ikgM) + +## Articles + +- [Creating beautiful Powershell Reports in Excel](https://dfinke.github.io/powershell/2019/07/31/Creating-beautiful-Powershell-Reports-in-Excel.html) +- [PowerShell Excel and Conditional Formatting](https://dfinke.github.io/powershell/2020/05/02/PowerShell-Excel-and-Conditional-Formatting.html) +- [Learn to Automate Excel like a Pro with PowerShell](https://dfinke.github.io/powershell/2019/08/29/Learn-to-Automate-Excel-like-a-Pro-with-PowerShell.html) \ No newline at end of file From ef7c8331f5aefea386f338938b3a627d1fcb4ca1 Mon Sep 17 00:00:00 2001 From: dfinke Date: Thu, 5 May 2022 18:34:56 -0400 Subject: [PATCH 123/140] add links for versions, donate etc --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dee9e11..63e94d3 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,14 @@ ![](images/logo.png) +
+ +[![](https://img.shields.io/powershellgallery/v/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) +[![](https://img.shields.io/powershellgallery/dt/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) +[![](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/dfinke/ImportExcel/tree/70ab9e46c776e96fb287682d5b9b4b51a0ec3bac/LICENSE.txt) +
Donate + +
# Overview Automate Excel with PowerShell without having Excel installed. Works on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier. @@ -148,4 +156,7 @@ ForEach-Object { $_.Value | Export-Csv ($_.key + '.csv') } - [Creating beautiful Powershell Reports in Excel](https://dfinke.github.io/powershell/2019/07/31/Creating-beautiful-Powershell-Reports-in-Excel.html) - [PowerShell Excel and Conditional Formatting](https://dfinke.github.io/powershell/2020/05/02/PowerShell-Excel-and-Conditional-Formatting.html) -- [Learn to Automate Excel like a Pro with PowerShell](https://dfinke.github.io/powershell/2019/08/29/Learn-to-Automate-Excel-like-a-Pro-with-PowerShell.html) \ No newline at end of file +- [Learn to Automate Excel like a Pro with PowerShell](https://dfinke.github.io/powershell/2019/08/29/Learn-to-Automate-Excel-like-a-Pro-with-PowerShell.html) + +## Contributing +Contributions are welcome! Open a pull request to add a feature, fix a bug, or open an issue to discuss a new feature or change. \ No newline at end of file From 6e38d97498dd0c81c74b1628e0138ec0ec1b96bb Mon Sep 17 00:00:00 2001 From: dfinke Date: Thu, 5 May 2022 18:35:59 -0400 Subject: [PATCH 124/140] fix header --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 63e94d3..d0a3591 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Donate
+ # Overview Automate Excel with PowerShell without having Excel installed. Works on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier. From aa0f0cf4e2ab0189ce748fb6bf3a33e897d13081 Mon Sep 17 00:00:00 2001 From: dfinke Date: Thu, 5 May 2022 18:36:19 -0400 Subject: [PATCH 125/140] layout --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index d0a3591..0209061 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,6 @@ [![](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/dfinke/ImportExcel/tree/70ab9e46c776e96fb287682d5b9b4b51a0ec3bac/LICENSE.txt) Donate -
- # Overview Automate Excel with PowerShell without having Excel installed. Works on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier. From 8ae92fba54eba99a758b5e8ba1f324bc2f207413 Mon Sep 17 00:00:00 2001 From: Doug Finke Date: Thu, 5 May 2022 21:19:24 -0400 Subject: [PATCH 126/140] spelling --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0209061..9e82d56 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ $data | Export-Excel .\salesData.xlsx -AutoNameRange -Show -PivotRows Region -Pi ## Create a separate CSV file for each Excel sheet -Do you have a Excel file with multiple sheets and you need to convert each sheet to CSV file? +Do you have an Excel file with multiple sheets and you need to convert each sheet to CSV file? ### Problem Solved From 27d69e75311da86b46ed18e713883222789ca22f Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 6 May 2022 13:01:12 -0400 Subject: [PATCH 127/140] Update pointing to examples --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0209061..944a7c5 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,10 @@ # Overview -Automate Excel with PowerShell without having Excel installed. Works on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier. +Automate Excel with PowerShell without having Excel installed. Works on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more just got a lot easier. + +## Examples +Check out [more than 100 examples](Examples/) on ways use this PowerShell Excel module. # Basic Usage ## Installation From 5777d907c431e3c80aac26b9525a86f17c3a67f4 Mon Sep 17 00:00:00 2001 From: dfinke Date: Fri, 6 May 2022 13:11:56 -0400 Subject: [PATCH 128/140] added Azure pipeline badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f05b576..6e439d2 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@
+[![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=update-read-me)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) [![](https://img.shields.io/powershellgallery/v/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) [![](https://img.shields.io/powershellgallery/dt/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) [![](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/dfinke/ImportExcel/tree/70ab9e46c776e96fb287682d5b9b4b51a0ec3bac/LICENSE.txt) From 59cf89b451de83ebdd5eb84d30190bf82ef101ee Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 7 May 2022 08:08:49 -0400 Subject: [PATCH 129/140] Additional updates --- README.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6e439d2..18414aa 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Automate Excel with PowerShell without having Excel installed. Works on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more just got a lot easier. ## Examples -Check out [more than 100 examples](Examples/) on ways use this PowerShell Excel module. +Check out [more than 100 examples](Examples/) on ways to make you more productive. # Basic Usage ## Installation @@ -118,7 +118,7 @@ $data | Export-Excel .\salesData.xlsx -AutoNameRange -Show -PivotRows Region -Pi ![](images/SalesDataChartPivotTable.png) -# Bonus Points +# Convert Excel data to other formats ## Create a separate CSV file for each Excel sheet @@ -135,7 +135,7 @@ This single line of PowerShell converts any number of sheets in an Excel workboo ForEach-Object { $_.Value | Export-Csv ($_.key + '.csv') } ``` -# Getting Started +# Additional Resources ## Videos @@ -146,8 +146,8 @@ ForEach-Object { $_.Value | Export-Csv ($_.key + '.csv') } ## More Videos -- [Look smarter: deliver your work in Excel](https://youtu.be/tu8Mfkwi8zI) - James O'Neill -- [Module Monday: ImportExcel](https://youtu.be/rBA_IeTmCb8?t=5) - Adam Driscoll +- [Look smarter: deliver your work in Excel](https://youtu.be/tu8Mfkwi8zI) - James O'Neill [@jamesoneill](https://twitter.com/jamesoneill) +- [Module Monday: ImportExcel](https://youtu.be/rBA_IeTmCb8?t=5) - Adam Driscoll [@adamdriscoll](https://twitter.com/adamdriscoll) - [Tutorials Excel Module Part 1](https://youtu.be/2cwBuYbZ3To) - [Tutorials Excel Module Part 2](https://youtu.be/8ojg-qjOnVI) - [Tutorials Excel Module Part 3](https://youtu.be/3IgASPD0UrQ) @@ -157,9 +157,16 @@ ForEach-Object { $_.Value | Export-Csv ($_.key + '.csv') } ## Articles -- [Creating beautiful Powershell Reports in Excel](https://dfinke.github.io/powershell/2019/07/31/Creating-beautiful-Powershell-Reports-in-Excel.html) -- [PowerShell Excel and Conditional Formatting](https://dfinke.github.io/powershell/2020/05/02/PowerShell-Excel-and-Conditional-Formatting.html) -- [Learn to Automate Excel like a Pro with PowerShell](https://dfinke.github.io/powershell/2019/08/29/Learn-to-Automate-Excel-like-a-Pro-with-PowerShell.html) +|Title|Author|Twitter| +|------|------|------| +|[More tricks with PowerShell and Excel](https://jamesone111.wordpress.com/2018/05/31/more-tricks-with-powershell-and-excel/)|James O'Neill|[@jamesoneill](https://twitter.com/jamesoneill)| +|[Using the Import-Excel module: Part 1 Importing](https://jamesone111.wordpress.com/2017/12/05/using-the-import-excel-part-1-importing/)|James O'Neill|[@jamesoneill](https://twitter.com/jamesoneill)| +|[Using the Import Excel module part 2: putting data into .XLSx files](https://jamesone111.wordpress.com/2017/12/11/using-the-import-excel-module-part-2-putting-data-into-xlsx-files/)|James O'Neill|[@jamesoneill](https://twitter.com/jamesoneill)| +|[Using the import Excel Module: Part 3, Pivots and charts, data and calculations](https://jamesone111.wordpress.com/2017/12/12/using-the-import-excel-module-part-3-pivots-and-charts-data-and-calculations/)|James O'Neill|[@jamesoneill](https://twitter.com/jamesoneill)| +|[Export AdventureWorksDW2017 to Excel for a Power BI Demo with Export-Excel](https://sqlvariant.com/2019/03/export-adventureworksdw2017-to-excel-for-a-powerbi-demo-with-export-excel-in-powershell/)|Aaron Nelson|[@sqlvariant](https://twitter.com/sqlvariant) +|[Creating beautiful Powershell Reports in Excel](https://dfinke.github.io/powershell/2019/07/31/Creating-beautiful-Powershell-Reports-in-Excel.html)|Doug Finke|[@dfinke](https://twitter.com/dfinke) +|[PowerShell Excel and Conditional Formatting](https://dfinke.github.io/powershell/2020/05/02/PowerShell-Excel-and-Conditional-Formatting.html)|Doug Finke|[@dfinke](https://twitter.com/dfinke) +|[Learn to Automate Excel like a Pro with PowerShell](https://dfinke.github.io/powershell/2019/08/29/Learn-to-Automate-Excel-like-a-Pro-with-PowerShell.html)|Doug Finke|[@dfinke](https://twitter.com/dfinke) ## Contributing -Contributions are welcome! Open a pull request to add a feature, fix a bug, or open an issue to discuss a new feature or change. \ No newline at end of file +Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change. \ No newline at end of file From 4f9b83f0e66135c92cd337f1a6879a407332e827 Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 7 May 2022 08:17:19 -0400 Subject: [PATCH 130/140] update logo --- README.md | 4 ++-- images/logoWithInstall.png | Bin 0 -> 35618 bytes 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 images/logoWithInstall.png diff --git a/README.md b/README.md index 18414aa..e7952f3 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # PowerShell and Excel -![](images/logo.png) +![](images/logoWithInstall.png)
-[![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=update-read-me)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) +[![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master)](https://dougfinke.visualstudio.com/ImportExcel/_build) [![](https://img.shields.io/powershellgallery/v/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) [![](https://img.shields.io/powershellgallery/dt/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) [![](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/dfinke/ImportExcel/tree/70ab9e46c776e96fb287682d5b9b4b51a0ec3bac/LICENSE.txt) diff --git a/images/logoWithInstall.png b/images/logoWithInstall.png new file mode 100644 index 0000000000000000000000000000000000000000..bb56ab757088b3e1f48241ca28036cf66375c7f9 GIT binary patch literal 35618 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 Ut Date: Sat, 7 May 2022 09:33:08 -0400 Subject: [PATCH 131/140] update xlsx link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e7952f3..8a722ba 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Do you have an Excel file with multiple sheets and you need to convert each shee ### Problem Solved -The `yearlyRetailSales.xlsx` has 12 sheets of retail data for the year. +The [yearlyRetailSales.xlsx](Examples%5CImport-Excel%5CyearlySales.xlsx) has 12 sheets of retail data for the year. This single line of PowerShell converts any number of sheets in an Excel workbook to separate CSV files. From f6bfabd96aeb6947b5ce1f42dc60a1025b6b19a7 Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 7 May 2022 09:34:02 -0400 Subject: [PATCH 132/140] remove encoding --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a722ba..a26bcec 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Do you have an Excel file with multiple sheets and you need to convert each shee ### Problem Solved -The [yearlyRetailSales.xlsx](Examples%5CImport-Excel%5CyearlySales.xlsx) has 12 sheets of retail data for the year. +The [yearlyRetailSales.xlsx](Examples\Import-Excel\yearlySales.xlsx) has 12 sheets of retail data for the year. This single line of PowerShell converts any number of sheets in an Excel workbook to separate CSV files. From 6628b55ce5b5da3b1fdf16a1396f2edc7f93df39 Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 7 May 2022 09:38:28 -0400 Subject: [PATCH 133/140] update link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a26bcec..6145065 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Do you have an Excel file with multiple sheets and you need to convert each shee ### Problem Solved -The [yearlyRetailSales.xlsx](Examples\Import-Excel\yearlySales.xlsx) has 12 sheets of retail data for the year. +The [yearlyRetailSales.xlsx](Examples\Import-Excel\) has 12 sheets of retail data for the year. This single line of PowerShell converts any number of sheets in an Excel workbook to separate CSV files. From 0b207548e046537ec3a74a8a85e2119c0afaad40 Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 7 May 2022 09:39:52 -0400 Subject: [PATCH 134/140] fix link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6145065..4acf25d 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Do you have an Excel file with multiple sheets and you need to convert each shee ### Problem Solved -The [yearlyRetailSales.xlsx](Examples\Import-Excel\) has 12 sheets of retail data for the year. +The [yearlyRetailSales.xlsx](Examples\Import-Excel) has 12 sheets of retail data for the year. This single line of PowerShell converts any number of sheets in an Excel workbook to separate CSV files. From ee3c8e768011262cd7b544c36e285338c16311ff Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 7 May 2022 09:40:18 -0400 Subject: [PATCH 135/140] use / --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4acf25d..7de7c13 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Do you have an Excel file with multiple sheets and you need to convert each shee ### Problem Solved -The [yearlyRetailSales.xlsx](Examples\Import-Excel) has 12 sheets of retail data for the year. +The [yearlyRetailSales.xlsx](Examples/Import-Excel) has 12 sheets of retail data for the year. This single line of PowerShell converts any number of sheets in an Excel workbook to separate CSV files. From cafaafd53d295f656488a16593a64882295f8144 Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 7 May 2022 09:45:16 -0400 Subject: [PATCH 136/140] add link to original readme --- README.md | 4 +- README.original.md | 1248 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1251 insertions(+), 1 deletion(-) create mode 100644 README.original.md diff --git a/README.md b/README.md index 7de7c13..063339e 100644 --- a/README.md +++ b/README.md @@ -169,4 +169,6 @@ ForEach-Object { $_.Value | Export-Csv ($_.key + '.csv') } |[Learn to Automate Excel like a Pro with PowerShell](https://dfinke.github.io/powershell/2019/08/29/Learn-to-Automate-Excel-like-a-Pro-with-PowerShell.html)|Doug Finke|[@dfinke](https://twitter.com/dfinke) ## Contributing -Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change. \ No newline at end of file +Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change. + +Original [README.md](./README.original.md) \ No newline at end of file diff --git a/README.original.md b/README.original.md new file mode 100644 index 0000000..b614b3b --- /dev/null +++ b/README.original.md @@ -0,0 +1,1248 @@ +# PowerShell + Excel = Better Together + + +Automate Excel via PowerShell without having Excel installed. Runs on Windows, Linux and MAC. Creating Tables, Pivot Tables, Charts and much more has just become a lot easier. + +
+ +[![](https://img.shields.io/powershellgallery/v/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) [![](https://img.shields.io/powershellgallery/dt/ImportExcel.svg)](https://www.powershellgallery.com/packages/ImportExcel) [![](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/dfinke/ImportExcel/tree/70ab9e46c776e96fb287682d5b9b4b51a0ec3bac/LICENSE.txt) + +
+ +| CI System | Environment | Status | +| :--- | :--- | :--- | +| Azure DevOps | Windows | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=Windows)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) | +| Azure DevOps | Windows \(Core\) | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=WindowsPSCore)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) | +| Azure DevOps | Ubuntu | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=Ubuntu)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) | +| Azure DevOps | macOS | [![Build Status](https://dougfinke.visualstudio.com/ImportExcel/_apis/build/status/dfinke.ImportExcel?branchName=master&jobName=macOS)](https://dougfinke.visualstudio.com/ImportExcel/_build/latest?definitionId=21&branchName=master) | + +
+ +Install from the [PowerShell Gallery](https://www.powershellgallery.com/packages/ImportExcel/). + +```powershell +Install-Module -Name ImportExcel +``` +### Donation + +If this project helped you reduce the time to get your job done, let me know, send a coffee. + +
+ +[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UCSB9YVPFSNCY) + +![](https://media.giphy.com/media/hpXxJ78YtpT0s/giphy.gif) + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/testimonial.png) + +## How to Videos + +* [PowerShell Excel Module - ImportExcel](https://www.youtube.com/watch?v=fvKKdIzJCws&list=PL5uoqS92stXioZw-u-ze_NtvSo0k0K0kq) + +Installation - + +**PowerShell V5 and Later** + +You can install the `ImportExcel` module directly from the PowerShell Gallery + +* \[Recommended\] Install to your personal PowerShell Modules folder + + ```text + Install-Module ImportExcel -scope CurrentUser + ``` + +* \[Requires Elevation\] Install for Everyone \(computer PowerShell Modules folder\) + + ```text + Install-Module ImportExcel + ``` + +## Continuous Integration Updates + +Big thanks to [Illy](https://github.com/ili101) for taking the Azure DevOps CI to the next level. Improved badges, improved matrix for cross platform OS testing and more. + +Plus, wiring the [PowerShell ScriptAnalyzer Excel report](https://github.com/dfinke/ImportExcel/pull/590#issuecomment-488659081) we built into each run as an artifact. + +![](.gitbook/assets/ScriptAnalyzerReport.png) + +## What's new 7.1.3 + +- Changed to `ProviderPath`. Thanks [Trevor Walker](https://github.com/sporkabob) + +## What's new 7.1.2 + +- `Get-ExcelFileSummary` - Gets summary information on an Excel file like number of rows, columns, and more + +``` +dir . -r *.xlsx | Get-ExcelFileSummary | ft + +ExcelFile WorksheetName Rows Columns Address Path +--------- ------------- ---- ------- ------- ---- +Grades.xlsx Sheet1 21 3 A1:C21 D:\temp\ExcelYouTube\Grades +GradesAverage.xlsx Sheet1 21 5 A1:E21 D:\temp\ExcelYouTube\Grades +AllShifts.xlsx Sheet1 21 2 A1:B21 D:\temp\ExcelYouTube\SeparateData +Shift_1.xlsx Sheet1 10 2 A1:B10 D:\temp\ExcelYouTube\SeparateData +Shift_2.xlsx Sheet1 8 2 A1:B8 D:\temp\ExcelYouTube\SeparateData +Shift_3.xlsx Sheet1 5 2 A1:B5 D:\temp\ExcelYouTube\SeparateData +Shifts.xlsx Shift_1 10 2 A1:B10 D:\temp\ExcelYouTube\SeparateData +Shifts.xlsx Shift_2 8 2 A1:B8 D:\temp\ExcelYouTube\SeparateData +``` + +## What's new 7.1.1 + +* Merged [Nate Ferrell](https://github.com/scrthq)'s Linux fix. Thanks! +* Moved `Export-MultipleExcelSheets` from psm1 to Examples/Experimental +* Deleted the CI build in Appveyor +* Thank you [Mikey Bronowski](https://github.com/MikeyBronowski) for + * Multiple sweeps + * Standardising casing of parameter names, and variables + * Plus updating > 50 of the examples and making them consistent. + +## What's new 7.1.0 + +Fixes, Updates and new Examples + +#### Fixed + +* Odd behavior on the return of Import-Excel function [https://github.com/dfinke/ImportExcel/issues/792](https://github.com/dfinke/ImportExcel/issues/792) +* Export-Excel -FreezeTopRow with -Title [https://github.com/dfinke/ImportExcel/issues/795](https://github.com/dfinke/ImportExcel/issues/795) +* Not importing when first row contains a 0 in a column [https://github.com/dfinke/ImportExcel/issues/802](https://github.com/dfinke/ImportExcel/issues/802) + +#### Updated + +* Add `-AsDate` support to `Import-Excel` and `ConvertFrom-ExcelSheet` + +#### New Examples + +| PS1 | Description | Link | +| :--- | :--- | :--- | +| Pester-To-XLSx | Runs Pester, collects the results, enriches it, and exports it to Excel | [Pester-To-XLSx.ps1](https://github.com/dfinke/ImportExcel/blob/fe68ddbb0dd86e9fd1f3bfe01c4d2b9ce5509510/Examples/Pester-To-XLSx.ps1) | +| DSUM | Sums up the numbers in a field \(column\) of records in a list or database that match conditions that you specify. | [DSUM.ps1](https://github.com/dfinke/ImportExcel/blob/12fa49e3142af2178ae1c6b18d8c757af0d629ac/Examples/ExcelBuiltIns/DSUM.ps1) | +| VLookup | Setups up a sheet, you enter the name of an item and the amount is looked up | [VLOOKUP.ps1](https://github.com/dfinke/ImportExcel/blob/e42f42fde92ca636af22252b753a8329f48e15f1/Examples/ExcelBuiltIns/VLOOKUP.ps1) | + +## What's new 7.0.1 + +More infrastructure improvements. + +* Refine pipeline script analysis +* Improve artifacts published +* Add manifest \(psd1\) checks + +## What's new 7.0.0 + +### Refactor + +* Remove all functions from the `psm1` +* Move functions into public subdirectory +* Align TDD and continuous integration workflow for this refactor +* Move help from functions to mdHelp and use [PlatyPS](https://www.powershellgallery.com/packages/platyPS) to generate external help file + +Thanks to [James O'Neill](https://twitter.com/jamesoneill) for the refactor and [Illy](https://twitter.com/ili_z) on the continuous integration. + +## What's new 6.5.3 + +Thanks again to the community for making this module even better. + +* [Fix import excel headers](https://github.com/dfinke/ImportExcel/pull/713) +* Numerous improvements for DataTables and exporting it to Excel [James O'Neill](https://twitter.com/jamesoneill) + * Names, styles, proper appending +* Handles marking the empty row on an empty table as dummy row +* Re-work code based on linting recommendations +* Update existing tests and add more +* Support PipelineVariable thanks to [Luc Dekens](https://twitter.com/LucD22) for reporting and [Ili](https://twitter.com/ili_z) for the PR +* Fix quoting in ConvertFromExcelToSQLInsert [beckerben](https://github.com/beckerben) + +## What's new 6.5.2 + +Thank you [uSlackr](https://github.com/uSlackr)ill + +* Fixes Column order issue \(plus tests\) for `Get-ExcelColumnName` + +Thank you [jhoneill](https://github.com/jhoneill) + +* Added -Force to Send-SQLDataToExcel so it sends something even if no rows are returned. \(see [\#703](https://github.com/dfinke/ImportExcel/issues/703)\) +* Added -asText to import-Excel see \(\#164\)\[[https://github.com/dfinke/ImportExcel/issues/164](https://github.com/dfinke/ImportExcel/issues/164)\] and multiple others +* Linux. Now set an environment variable if the support needed for Autosize is present, and use that Environment variable to decide to skip autosize operations. +* Fixed tests which needed autosize to work so they skip of the environment variable is set. +* Fixed another break where on azure the module never loaded. +* Add a comment to ci.ps1 re better .NET version detection and left some commented out code. + +Other + +* Added the example [ReadAllSheets.ps1](https://github.com/dfinke/ImportExcel/tree/master/Examples/ReadAllSheets) based on this thread [https://github.com/dfinke/ImportExcel/issues/678](https://github.com/dfinke/ImportExcel/issues/678) + +## What's new 6.5.0 + +This is now using the latest version of EPPlus. Unit tests are updated and passing, if you hit problems, please open an issue. You can rollback to an older version from the PowerShell Gallery if you are blocked. + +* Unit tests were updated and fixed +* "Set-WorksheetProtection" is now switched on +* Made a change to make Set-Excel range more friendly when Auto Sizing on non-windows platforms +* Fixed - Windows only tests don't attempt to run on non-windows systems +* Tests based on Get-Process don't attempt to run if <20 processes are returned +* If $env:TEMP is not set \(as will be the case on Linux\) +* Join-Path if used so paths are built with / or with as suits the OS where the test is running. +* Excel Sparklines now supported, check out the examples [SalesByQuarter](https://github.com/dfinke/ImportExcel/blob/master/Examples/Sparklines/SalesByQuarter.ps1) and [Sparklines](https://github.com/dfinke/ImportExcel/blob/master/Examples/Sparklines/Sparklines.ps1). + +![](.gitbook/assets/Sparklines.png) + +## What's new 6.2.4 + +Sensible parameter defaults, make your life easier and gets things done faster. + +* Thank you to [DomRRuggeri](https://github.com/DomRRuggeri) for the initial Out-Excel PR and kicking off the conversation on the improvements. +* Thank you to [ili101](https://github.com/ili101) for refactoring and improving the defaults, and adding the tests for parameters. +* Creates a table, with filtering +* Chooses a `TableStyle` +* Displays the Excel spreadsheet automatically + +```text +Get-Process | select Company, Name, Handles | Export-Excel +``` + +![image](.gitbook/assets/ImproveNowDefaults.png) + +## What's new 6.2.3 + +Thank you [jhoneill](https://github.com/jhoneill). + +* Refactored copy sheet and added pipe support +* Add `ClearAll` to `Set-ExcelRange` +* Fix broken test & regression for `passwords` + * **Note**: Passwords do not work on `pwsh`. The EPPlus library does not support these dotnet core APIs at this time. + +## What's new 6.2.2 + +* Added requested feature, chart trendlines. + * [Example PowerShell script](https://github.com/dfinke/ImportExcel/blob/master/Examples/Charts/NumberOfVisitors.ps1) + +![](.gitbook/assets/ChartTrendlines.png) + +* Fixed Import-Excel and relative path issue, added unit tests. + +## What's new 6.2.0 + +Thank you to [James O'Neill](https://github.com/jhoneill) + +* Fixed, Import-Excel can read xlsx files even if already open in Excel +* Added `New-ExcelStyle`, plus `-Style` to `Export-Excel` and `-Merge` to `Set-ExcelRange` +* Added [Style Examples](https://github.com/dfinke/ImportExcel/tree/master/Examples/Styles) + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/NewExcelStyle.png) + +## What's new 6.1.0 + +Thank you to [James O'Neill](https://github.com/jhoneill) + +* Instead of specifying a path provides an Excel Package object \(from `Open-ExcelPackage`\), using this avoids re-reading the whole file when importing multiple parts of it. To allow multiple read operations `Import-Excel` does NOT close the package, and you should use `Close-ExcelPackage -noSave` to close it. + +## What's new 6.0.0 + +Thank you to [James O'Neill](https://github.com/jhoneill) for the optimizations, and refactoring leading to a _**~10x**_ speed increase. Thanks to [ili101](https://github.com/ili101) for earlier PRs that provided the ground work for this. + +* Performance improvement to `Export-Excel` see [\#506](https://github.com/dfinke/ImportExcel/issues/506) and [\#555](https://github.com/dfinke/ImportExcel/issues/555). This has meant taking code in Add-CellValue back into process block of `Export-Excel`, as the overhead of calling the function was a lot greater than time executing the code inside it. [Blog post to follow](https://jamesone111.wordpress.com/). Some tests are showing a _**~10x**_ speed increase. [\#572](https://github.com/dfinke/ImportExcel/issues/572) was about a broken \#region tag in this part of the code and that has been cleaned up in the process. +* `Export-Excel` now has an -InputObject parameter \(this was previously -TargetData , which is now an alias for InputObject\). If the `inputobject` is an array, each item will be inserted, so you can run `export-excel -inputobject $x` rather than `$x | Export-Excel`, and if it is a `system.data.datatable` object it will be inserted directly rather than cell-by-cell. `Send-SQLDataToExcel` takes advantage of this new functionality. There are simple tests for these new items +* `Export-Excel` previously assumed `-Now` if there were no other parameters, it will now assume `-Now` if there is no `-Path` or `-ExcelPackage`. The .PSD1 file now itemizes the items exported by the module [\#557](https://github.com/dfinke/ImportExcel/issues/557) + +## What's new 5.4.5 + +Thank you to [James O'Neill](https://github.com/jhoneill) for the great additions. + +* Modified Send-SQLDataToExcel so it creates tables and ranges itself; previously it relied on export-excel to do this which cause problems when adding data to an existing sheet \(\#555\) +* Added new command Add-ExcelDataValidation which will apply different data-validation rules to ranges of cells +* Changed the export behavior so that \(1\) attempts to convert to a number only apply if the the value was a string; \(2\) Nulls are no longer converted to an empty string \(3\) there is a specific check for URIs and not just text which is a valid URI. Using UNC names in hyperlinks remains problematic. +* Changed the behavior of AutoSize in export excel so it only applies to the exported columns. Previously if something was exported next to pre-existing data, AutoSize would resize the whole sheet, potentially undoing things which had been set on the earlier data. If anyone relied on this behavior they will need to explicitly tell the sheet to auto size with $sheet.cells.autofitColumns. \(where $sheet points to the sheet, it might be $ExcelPackage.Workbook.Worksheets\['Name'\]\) +* In Compare-Worksheet,the Key for comparing the sheets can now be written as a hash table with an expression - it is used with a Group-Object command so if it is valid in Group-Object it should be accepted; this allows the creation of composite keys when data being compared doesn't have a column which uniquely identifies rows. +* In Set-ExcelRange , added a 'Locked' option equivalent to the checkbox on the Protection Tab of the format cells dialog box in Excel. +* Created a Set-WorksheetProtection function. This gives the same options the protection dialog in Excel but is 0.9 release at the moment. + +### New Example + +* Added [MutipleValidations.ps1](https://github.com/dfinke/ImportExcel/blob/master/Examples/ExcelDataValidation/MutipleValidations.ps1). Culled from the `tests`. + +## What's new 5.4.4 + +* Fix issue when only a single property is piped into Export-Excel +* Fix issue in `Copy-ExcelWorksheet`, close the `$Stream` + +## What's new 5.4.3 + +* Added Remove-Worksheet: Removes one or more worksheets from one or more workbooks + +## What's new 5.4.2 + +* Added parameters -GroupDateRow and -GroupDatePart & -GroupNumericRow, -GroupNumericMin, -GroupNumericMax and -GroupNumericInterval + + to Add-PivotTable and New-PivotTableDefinition. The date ones gather dates of the same year and/or quarter and/or month and/or day etc. + + the number ones group numbers into bands, starting at Min, and going up steps specified by Interval. Added tests and help for these. + +* Set-ExcelRow and Set-ExcelColumn now check that the worksheet name they passed exists in the workbook. + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/cf964e3e4f761ca4058c4a4b809e2206b16709da/images/GroupingNumeric.png) + +## What's new 5.4.0 + +* Thank you to Conrad Agramont, Twitter: [@AGramont](https://twitter.com/@AGramont) for the `AddMultiWorkSheet.ps1` example. Much appreciated! +* Fixed several more bugs where parameters were ignored if passed a zero value +* Fixed bug where chart series headers could not come form a cell reference \(=Sheet1!Z10 now works as a header reference\) +* Add-Chart will now allow a single X range, or as many X ranges as there are Y ranges. +* Merge-MultipleSheets is more robust. +* Set-ExcelRow and Set-ExcelColumn trap attempts to process a sheet with no rows/columns. +* Help has been proof-read \(thanks to Mrs. @Jhoneill !\). + +## What's new 5.3.4 + +* HotFix for parameter PivotTableStyle should be PivotTableStyle [https://github.com/dfinke/ImportExcel/issues/453](https://github.com/dfinke/ImportExcel/issues/453) + +## What's new 5.3.3 + +* Thank you to \(lazywinadmin\)\[[https://github.com/lazywinadmin](https://github.com/lazywinadmin)\] - Expand aliases in examples and elsewhere +* In Export-Excel fixed a bug where -AutoNameRange on pre-existing data included the header in the range. +* In Export-Excel fixed a bug which caused a zero, null, or empty string in a list of simple objects to be skipped. +* In Export-Excel improved the behaviour when a new worksheet is created without data, and Tables etc are added to it. +* In Join-Worksheet: added argument completer to -TitleBackgroundColor and set default for -TitleBackgroundStyle to 'Solid'. +* In Add-Excel chart, New-ExcelChart, tests and Examples fixed mis-spelling of "Position" +* In Send-SqlDataToExcel: improved robustness of check for no data returned. +* In Set-ExcelColumn: -column can come from the pipeline \(supporting an array introduces complications for supporting script blocks\); -AutoNameRange no longer requires heading to specified \(so you can do 1..10 \| Set-ExcelColumn -AutoNameRange \); In Set-ExcelRow: -Row can come from the pipeline +* Improved test coverage \(back over 80%\). +* Help and example improvements. In "Index - music.ps1" the module for querying the index can be downloaded from PowerShell gallery \#requires set to demand it. In SQL+FillColumns+Pivot\example2.ps1 the GetSQL module can be downloaded and \#Requires has been set. The F1 results spreadsheet is available from one drive and a link is provided. +* Added Azure DevOps continuous integration and badges + +## What's new in Release 5.3 + +* Help improvements and tidying up of examples and extra examples +* Open-Excel Package and Add-Worksheet now add worksheets as script properties so `$Excel = Open-ExcelPackage -path test.xlsx ; $excel.sheet1` will return the sheet named "sheet1" `$Excel.SheetName` is a script property which is defined as `$this.workbook.worksheets["Sheetname"]` +* Renamed Set-Column to `Set-ExcelColumn`, Set-Row to `Set-ExcelRow`, and Set-Format, to `Set-ExcelRange`. Added aliases so the old names still work. +* `Set-ExcelRange` \(or set-Format\) used "Address" and "Range" incorrectly. There is now a single parameter `-Range`, with an alias of "Address". If the worksheet parameter is present, the function accepts a string specifying cells \("A1:Z10"\) or a the name of range. Without the worksheet it accepts an object representing a named range or a Table; or a tables's address, or part of the worksheet.cells collection. +* `Add-ConditionalFormatting`: Used "address" correctly, and it will accept ranges in the address parameter \(range is now an alias for address\). It now wraps conditional value strings in quotes when needed \(for = <= >= operations string needs to be in double quotes see issue \#424\). Parameter intellisense has been improved. There are new parameters: `-StopIfTrue` and `-Priority` and support for using the `-Reverse` parameter with Color-scale rules \(issue \#430\). Booleans in the sheet are now supported as the value for a condition. Also brought the two different kinds of condition together inside Export-Excel, and fixed a bug where named-ranges didn't work in some places. In `New-ConditionalText`, more types of conditional format are supported, and the argument completer for -ConditionalTextColor was missing and has been added. +* Improved handling of hyperlinks in `Export-Excel` \(see issue \#426\)s +* `Export-Excel` has better checking of Table and PivotTable names \(for uniqueness\) and a new test in quick charts that there is suitable data for charting. It also accepts hash tables for chart, pivot table and conditional formatting parameters which are splatted into the functions which add these. +* Moved logic for adding a named-range out of Export-Excel and into a new function named `Add-ExcelName`, and logic for adding a table into a function named `Add-ExcelTable`; this is to make it easier to do these things independently of Export-Excel, but minimize duplication. The Add-ExcelTable command has extra parameters to toggle the options from table tools toolbar \(show totals etc.\) and set options in the totals row. +* Moved PivotTable Functions out of Export-Excel.PS1 into their own file and moved Add-ExcelChart out of Export-Excel.ps1 into New-ExcelChart.ps1 +* Fixed bug in Merge-MultipleSheets where background pattern was set to None, making background color invisible. +* Fixed issues where formatting could be reset when using Export-Excel to manipulate an existing sheet without appending data; this applied to number-formats and tables. +* `Add-PivotTable` has some new parameters `-PassThru` returns the pivot table \(e.g. to allow names /sort orders of data series to be tweaked \) `-Address` allows Pivot to be placed on an existing sheet; `-PivotTableStyle` allows a change from "Medium6", `-PivotNumberFormat` formats data cells. It is more flexible about how the source data is specified - copying the range options in Set-ExcelRange. `Add-ExcelChart` is now used for creating PivotCharts, and `-PivotChartDefinition` allows a definition created with `New-ExcelChartDefinition` to be used when setting up a PivotTable. This opens up all the things that Add-ExcelChart can do without duplicating the parameters on Add-Pivot table and Export-Excel. Definition, TableStyle, Numberformat and ChartDefiniton can be used in `New-PivotTableDefinition` . +* `Add-ExcelChart` now supports -PassThru to return the chart for tweaking after creation; there is now a -PivotTable parameter to allow Add-PivotTable to call the code in Add-ExcelChart. And in `New-ExcelChartDefinition` Legend parameters \(for size, bold & position \) are now supported +* ChartDefinition and conditional formatting parameters can now be hashtables - anything that splats Add-ExcelChart or Add-ConditionalFormatting, it should be acceptable as a definition. + +## What's new in Release 5.2 + +* Value does not need to be mandatory in Set-Row or Set-Column, also tidied their parameters a little. +* Added support for array formulas in Set-Format \(it really should be set range now that it sets values, formulas and hyperlinks - that can go on the to-do list \) +* Fixed a bug with -Append in Export-Excel which caused it to overwrite the last row if the new data was a simple type. +* NumberFormat in Export-Excel now sets the default for on a new / blank sheet; but \[still\] sets individual cells when adding to a sheet +* Added support for timespans in Export excel ; set as elapsed hours, mins, secs \[h\]:mm:sss +* In Export-Excel improved the catch-all handler for insuring values to cope better with nested objects \(\#419\) and reduce the number of parse operations +* Added -Calculate switch to Export-Excel and Close-Excel Package; EPPlus needs formulas to OMIT the leading = sign so where formula is set it now strips a leading = sign +* Added -PivotTotals parameter where there was already -NoTotalsInPivot new one allows None, Both, Rows, Columns. \(\#415\) +* When appending Export-Excel only extended tables and ranges if they were explicitly specified. It now does it automatically. +* Compare and Merge worksheet originally had a problem with > 26 columns, I fixed merge turns out I hadn't fixed compare ... I have now +* Fixed bug where Export-Excel would not recognize it had to set $TitleFillPattern - made the default 'Solid' +* ExcludeProperty in Export-Excel now supports wildcards. +* Added DateTime to the list of types which can be exported as single column. +* Added Password support to Open- and Close-ExcelPackage \(password was not doing anything in Export-Excel\) +* Gave Expand-NumberFormat a better grasp of currency layouts - it follows .NET which is not always the same as Excel would set:-\( + +## What's new in Release 5.1.1 + +* Set-Row and Set-Column will now create hyperlinks and insert dates correctly +* Import-Excel now has an argument completer for Worksheet name - this can be slow on large files +* The NumberFormat parameter \(in Export-Excel, Set-Row, Set-Column, Set-Format and Add-ConditionalFormat\) and X&YAxisNumberFormat parameters \(in New-ExcelChartDefinition and Add-ExcelChart\) now have an argument completer and the names Currency, Number, Percentage, Scientific, Fraction, Short Date ,Short time,Long time, Date-Time and Text will be converted to the correct Excel formatting strings. +* Added new function Select-Worksheet to make a named sheet active: Added -Activate switch to Add-Worksheet, to make current sheet active, Export-Excel and Add-PivotTable support -Activate and pass it to Add-Worksheet, and New-PivotTableDefinition allows it to be part of the Pivot TableDefinition. +* Fixed a bug in Set-Format which caused -Hidden not to work +* Made the same changes to Add-Conditional format as set format so -switch:$false is processed, and 0 enums and values are processed correctly +* In Export-Excel, wrapped calls to Add-CellValue in a try catch so a value which causes an issue doesn't crash the whole export but generates a warning instead \(\#410\) . +* Additional tests. + +## What's new to July 18 + +* Changed parameter evaluation in Set-Format to support -bold:$false \(and other switches so that if false is specified the attribute will be removed \), and to bug were enums with a value of zero, and other zero parameters were not set. +* Moved chart creation into its own function \(Add-Excel chart\) within Export-Excel.ps1. Renamed New-Excelchart to New-ExcelChartDefinition to make it clearer that it is not making anything in the workbook \(but for compatibility put an alias of New-ExcelChart in so existing code does not break\). Found that -Header does nothing, so it isn't Add-Excel chart and there is a message that does nothing in New-ExcelChartDefinition . +* Added -BarChart -ColumnChart -LineChart -PieChart parameters to Export-Excel for quick charts without giving a full chart definition. +* Added parameters for managing chart Axes and legend +* Added some chart tests to Export-Excel.tests.ps1. \(but tests & examples for quick charts , axes or legends still on the to do list \) +* Fixed some bad code which had been checked-in in-error and caused adding charts to break. \(This was not seen outside GitHub \#377\) +* Added "Reverse" parameter to Add-ConditionalFormatting ; and added -PassThru to make it easier to modify details of conditional formatting rules after creation \(\#396\) +* Refactored ConditionalFormatting code in Export excel to use Add-ConditionalFormatting. +* Rewrote Copy-ExcelWorksheet to use copy functionality rather than import \| export \(395\) +* Found sorts could be inconsistent in Merge-MultipleWorksheet, so now sort on more columns. +* Fixed a bug introduced into Compare-Worksheet by the change described in the June changes below, this meant the font color was only being set in one sheet, when a row was changed. Also found that the PowerShell ISE and shell return Compare-Object results in different sequences which broke some tests. Applied a sort to ensure things are in a predictable order. \(\#375\) +* Removed \(2\) calls to Get-ExcelColumnName \(Removed and then restored function itself\) +* Fixed an issue in Export-Excel where formulas were inserted as strings if "NoNumberConversion" is applied \(\#374\), and made sure formatting is applied to formula cells +* Fixed an issue with parameter sets in Export-Excel not being determined correctly in some cases \(I think this had been resolved before and might have regressed\) +* Reverted the \[double\]::tryParse in export excel to the previous \(longer\) way, as the shorter way was not behaving correctly with with the number formats in certain regions. \(also \#374\) +* Changed Table, Range and AutoRangeNames to apply to whole data area if no data has been inserted OR to inserted data only if it has.\(\#376\) This means that if there are multiple inserts only inserted data is touched, rather than going as far down and/or right as the furthest used cell. Added a test for this. +* Added more of the Parameters from Export-Excel to Join-worksheet, join just calls export-excel with these parameters so there is no code behind them \(\#383\) +* Added more of the Parameters from Export-Excel to Send-SQLDataToExcel, send just calls export-excel with these parameters... +* Added support for passing a System.Data.DataTable directly to Send-SQLDataToExcel +* Fixed a bug in Merge-MultipleSheets where if the key was "name", columns like "displayName" would not be processed correctly, nor would names like "something\_ROW". Added tests for Compare, Merge and Join Worksheet +* Add-Worksheet , fixed a regression with move-after \(\#392\), changed way default worksheet name is decided, so if none is specified, and an existing worksheet is copied \(see June additions\) and the name doesn't already exist, the original sheet name will be kept. \(\#393\) If no name is given an a blank sheet is created, then it will be named sheetX where X is the number of the sheet \(so if you have sheets FOO and BAR the new sheet will be Sheet3\). + +## New in June 18 + +* New commands - Diff , Merge and Join + * `Compare-Worksheet` \(introduced in 5.0\) uses the built in `Compare-object` command, to output a command-line DIFF and/or color the worksheet to show differences. For example, if my sheets are Windows services the _extra_ rows or rows where the startup status has changed get highlighted + * `Merge-Worksheet` \(also introduced in 5.0\) joins two lumps, side by highlighting the differences. So now I can have server A's services and Server Bs Services on the same page. I figured out a way to do multiple sheets. So I can have Server A,B,C,D on one page :-\) that is `Merge-MultpleSheets` + + For this release I've fixed heaven only knows how many typos and proof reading errors in the help for these two, the only code change is to fix a bug if two worksheets have different names, are in different files and the Comparison sends the delta in the second back before the one in first, then highlighting changed properties could throw an error. Correcting the spelling of Merge-MultipleSheets is potentially a breaking change \(and it is still plural!\) + + also fixed a bug in compare worksheet where color might not be applied correctly when the worksheets came from different files and had different name. + + * `Join-Worksheet` is **new** for this release. At it's simplest it copies all the data in Worksheet A to the end of Worksheet B +* Add-Worksheet + * I have moved this from ImportExcel.psm1 to ExportExcel.ps1 and it now can move a new worksheet to the right place, and can copy an existing worksheet \(from the same or a different workbook\) to a new one, and I set the Set return-type to aid intellisense +* New-PivotTableDefinition + * Now Supports `-PivotFilter` and `-PivotDataToColumn`, `-ChartHeight/width` `-ChartRow/Column`, `-ChartRow/ColumnPixelOffset` parameters +* Set-Format + * Fixed a bug where the `-address` parameter had to be named, although the examples in `export-excel` help showed it working by position \(which works now. \) +* Export-Excel + * I've done some re-factoring + 1. I "flattened out" small "called-once" functions , add-title, convert-toNumber and Stop-ExcelProcess. + 2. It now uses Add-Worksheet, Open-ExcelPackage and Add-ConditionalFormat instead of duplicating their functionality. + 3. I've moved the PivotTable functionality \(which was doubled up\) out to a new function "Add-PivotTable" which supports some extra parameters PivotFilter and PivotDataToColumn, ChartHeight/width ChartRow/Column, ChartRow/ColumnPixelOffsets. + 4. I've made the try{} catch{} blocks cover smaller blocks of code to give a better idea where a failure happened, some of these now Warn instead of throwing - I'd rather save the data with warnings than throw it away because we can't add a chart. Along with this I've added some extra write-verbose messages + * Bad column-names specified for Pivots now generate warnings instead of throwing. + * Fixed issues when pivot tables / charts already exist and an export tries to create them again. + * Fixed issue where AutoNamedRange, NamedRange, and TableName do not work when appending to a sheet which already contains the range\(s\) / table + * Fixed issue where AutoNamedRange may try to create ranges with an illegal name. + * Added check for illegal characters in RangeName or Table Name \(replace them with "\_"\), changed tablename validation to allow spaces and applied same validation to RangeName + * Fixed a bug where BoldTopRow is always bolds row 1 even if the export is told to start at a lower row. + * Fixed a bug where titles throw pivot table creation out of alignment. + * Fixed a bug where Append can overwrite the last rows of data if the initial export had blank rows at the top of the sheet. + * Removed the need to specify a fill type when specifying a title background color + * Added MoveToStart, MoveToEnd, MoveBefore and MoveAfter Parameters - these go straight through to Add worksheet + * Added "NoScriptOrAliasProperties" "DisplayPropertySet" switches \(names subject to change\) - combined with ExcludeProperty these are a quick way to reduce the data exported \(and speed things up\) + * Added PivotTableName Switch \(in line with 5.0.1 release\) + * Add-CellValue now understands URI item properties. If a property is of type URI it is created as a hyperlink to speed up Add-CellValue + * Commented out the write verbose statements even if verbose is silenced they cause a significant performance impact and if it's on they will cause a flood of messages. + * Re-ordered the choices in the switch and added an option to say "If it is numeric already post it as is" + * Added an option to only set the number format if doesn't match the default for the sheet. +* Export-Excel Pester Tests + * I have converted examples 1-9, 11 and 13 from Export-Excel help into tests and have added some additional tests, and extra parameters to the example command to get better test coverage. The test so far has 184 "should" conditions grouped as 58 "IT" statements; but is still a work in progress. +* Compare-Worksheet pester tests +* [James O'Neill](https://twitter.com/jamesoneill) added `Compare-Worksheet` + * Compares two worksheets with the same name in different files. + +**4/22/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 +* [Nasir Zubair](https://github.com/nzubair) added `ConvertEmptyStringsToNull` to the function `ConvertFrom-ExcelToSQLInsert` + * If specified, cells without any data are replaced with NULL, instead of an empty string. This is to address behaviors in certain DBMS where an empty string is insert as 0 for INT column, instead of a NULL value. + +**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, bottom, left and right + * Added parameters to set `value` and `formula` + +```text +$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. + +```text +$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` **$false** 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. + +```text + 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. + +\(Check out the examples `help Export-Excel -Examples`\) + +* New parameter `Package` allows an ExcelPackage object returned by `-passThru` to be passed in +* New parameter `ExcludeProperty` to remove unwanted properties without needing to go through `select-object` +* New parameter `Append` code to read the existing headers and move the insertion point below the current data +* New parameter `ClearSheet` which removes the worksheet and any past data +* Remove any existing Pivot table before trying to \[re\]create it +* Check for inserting a pivot table so if `-InsertPivotChart` is specified it implies `-InsertPivotTable` + +\(Check out the examples `help Export-Excel -Examples`\) + +* New function `Export-Charts` \(requires Excel to be installed\) - Export Excel charts out as JPG files +* New function `Add-ConditionalFormatting` Adds conditional formatting to worksheet +* New function `Set-Format` Applies Number, font, alignment and color formatting to a range of Excel Cells +* `ColorCompletion` an argument completer for `Colors` for params across functions + +I also worked out the parameters so you can do this, which is the same as passing `-Now`. It creates an Excel file name for you, does an auto fit and sets up filters. + +`ps | select Company, Handles | Export-Excel` + +**10/13/2017** + +Added `New-PivotTableDefinition`. You can create and wire up a PivotTable to a WorkSheet. You can also create as many PivotTable Worksheets to point a one Worksheet. Or, you create many Worksheets and many corresponding PivotTable Worksheets. + +Here you can create a WorkSheet with the data from `Get-Service`. Then create four PivotTables, pointing to the data each pivoting on a different dimension and showing a different chart + +```text +$base = @{ + SourceWorkSheet = 'gsv' + PivotData = @{'Status' = 'count'} + IncludePivotChart = $true +} + +$ptd = [ordered]@{} + +$ptd += New-PivotTableDefinition @base servicetype -PivotRows servicetype -ChartType Area3D +$ptd += New-PivotTableDefinition @base status -PivotRows status -ChartType PieExploded3D +$ptd += New-PivotTableDefinition @base starttype -PivotRows starttype -ChartType BarClustered3D +$ptd += New-PivotTableDefinition @base canstop -PivotRows canstop -ChartType ConeColStacked + +Get-Service | Export-Excel -path $file -WorkSheetname gsv -Show -PivotTableDefinition $ptd +``` + +**10/4/2017** + +Thanks to [https://github.com/ili101](https://github.com/ili101) : + +* Fix Bug, Unable to find type \[PSPlot\] +* Fix Bug, AutoFilter with TableName create corrupted Excel file. + +**10/2/2017** + +Thanks to [Jeremy Brun](https://github.com/jeremytbrun) Fixed issues related to use of -Title parameter combined with column formatting parameters. + +* [Issue \#182](https://github.com/dfinke/ImportExcel/issues/182) +* [Issue \#89](https://github.com/dfinke/ImportExcel/issues/89) + +**9/28/2017 \(Version 4.0.1\)** + +* Added a new parameter called `Password` to import password protected files +* Added even more `Pester` tests for a more robust and bug free module +* Renamed parameter 'TopRow' to 'StartRow' + + This allows us to be more concise when new parameters \('StartColumn', ..\) will be added in the future Your code will not break after the update, because we added an alias for backward compatibility + +Special thanks to [robinmalik](https://github.com/robinmalik) for providing us with [the code](https://github.com/dfinke/ImportExcel/issues/174) to implement this new feature. A high five to [DarkLite1](https://github.com/DarkLite1) for the implementation. + +**9/12/2017 \(Version 4.0.0\)** + +Super thanks and hat tip to [DarkLite1](https://github.com/DarkLite1). There is now a new and improved `Import-Excel`, not only in functionality, but also improved readability, examples and more. Not only that, he's been running it in production in his company for a number of weeks! + +_Added_ `Update-FirstObjectProperties` Updates the first object to contain all the properties of the object with the most properties in the array. Check out the help. + +_**Breaking Changes**_: Due to a big portion of the code that is rewritten some slightly different behavior can be expected from the `Import-Excel` function. This is especially true for importing empty Excel files with or without using the `TopRow` parameter. To make sure that your code is still valid, please check the examples in the help or the accompanying `Pester` test file. + +Moving forward, we are planning to include automatic testing with the help of `Pester`, `Appveyor` and `Travis`. From now on any changes in the module will have to be accompanied by the corresponding `Pester` tests to avoid breakages of code and functionality. This is in preparation for new features coming down the road. + +**7/3/2017** + +Thanks to [Mikkel Nordberg](https://www.linkedin.com/in/mikkelnordberg). He contributed a `ConvertTo-ExcelXlsx`. To use it, Excel needs to be installed. The function converts the older Excel file format ending in `.xls` to the new format ending in `.xlsx`. + +**6/15/2017** + +Huge thank you to [DarkLite1](https://github.com/DarkLite1)! Refactoring of code, adding help, adding features, fixing bugs. Specifically this long outstanding one: + +[Export-Excel: Numeric values not correct](https://github.com/dfinke/ImportExcel/issues/168) + +It is fantastic to work with people like `DarkLite1` in the community, to help make the module so much better. A hat to you. + +Another shout out to [Damian Reeves](https://twitter.com/DamReev)! His questions turn into great features. He asked if it was possible to import an Excel worksheet and transform the data into SQL `INSERT` statements. We can now answer that question with a big YES! + +```text +ConvertFrom-ExcelToSQLInsert People .\testSQLGen.xlsx +``` + +```text +INSERT INTO People ('First', 'Last', 'The Zip') Values('John', 'Doe', '12345'); +INSERT INTO People ('First', 'Last', 'The Zip') Values('Jim', 'Doe', '12345'); +INSERT INTO People ('First', 'Last', 'The Zip') Values('Tom', 'Doe', '12345'); +INSERT INTO People ('First', 'Last', 'The Zip') Values('Harry', 'Doe', '12345'); +INSERT INTO People ('First', 'Last', 'The Zip') Values('Jane', 'Doe', '12345'); +``` + +### Bonus Points + +Use the underlying `ConvertFrom-ExcelData` function and you can use a scriptblock to format the data however you want. + +```text +ConvertFrom-ExcelData .\testSQLGen.xlsx { + param($propertyNames, $record) + + $reportRecord = @() + foreach ($pn in $propertyNames) { + $reportRecord += "{0}: {1}" -f $pn, $record.$pn + } + $reportRecord +="" + $reportRecord -join "`r`n" +} +``` + +Generates + +```text +First: John +Last: Doe +The Zip: 12345 + +First: Jim +Last: Doe +The Zip: 12345 + +First: Tom +Last: Doe +The Zip: 12345 + +First: Harry +Last: Doe +The Zip: 12345 + +First: Jane +Last: Doe +The Zip: 12345 +``` + +**2/2/2017** + +Thank you to [DarkLite1](https://github.com/DarkLite1) for more updates + +* TableName with parameter validation, throws an error when the TableName: + * Starts with something else then a letter + * Is NULL or empty + * Contains spaces +* Numeric parsing now uses `CurrentInfo` to use the system settings + +**2/14/2017** + +Big thanks to [DarkLite1](https://github.com/DarkLite1) for some great updates + +* `-DataOnly` switch added to `Import-Excel`. When used it will only generate objects for rows that contain text values, not for empty rows or columns. +* `Get-ExcelWorkBookInfo` - retrieves information of an Excel workbook. + + ```text + Get-ExcelWorkbookInfo .\Test.xlsx + + CorePropertiesXml : #document + Title : + Subject : + Author : Konica Minolta User + Comments : + Keywords : + LastModifiedBy : Bond, James (London) GBR + LastPrinted : 2017-01-21T12:36:11Z + Created : 17/01/2017 13:51:32 + Category : + Status : + ExtendedPropertiesXml : #document + Application : Microsoft Excel + HyperlinkBase : + AppVersion : 14.0300 + Company : Secret Service + Manager : + Modified : 10/02/2017 12:45:37 + CustomPropertiesXml : #document + ``` + +**12/22/2016** + +* Added `-Now` switch. This short cuts the process, automatically creating a temp file and enables the `-Show`, `-AutoFilter`, `-AutoSize` switches. + +```text +Get-Process | Select Company, Handles | Export-Excel -Now +``` + +* Added ScriptBlocks for coloring cells. Check out [Examples](https://github.com/dfinke/ImportExcel/tree/master/Examples/FormatCellStyles) + +```text +Get-Process | + Select-Object Company,Handles,PM, NPM| + Export-Excel $xlfile -Show -AutoSize -CellStyleSB { + param( + $workSheet, + $totalRows, + $lastColumn + ) + + Set-CellStyle $workSheet 1 $LastColumn Solid Cyan + + foreach($row in (2..$totalRows | Where-Object {$_ % 2 -eq 0})) { + Set-CellStyle $workSheet $row $LastColumn Solid Gray + } + + foreach($row in (2..$totalRows | Where-Object {$_ % 2 -eq 1})) { + Set-CellStyle $workSheet $row $LastColumn Solid LightGray + } + } +``` + +![](https://github.com/dfinke/ImportExcel/blob/master/images/CellFormatting.png?raw=true) + +**9/28/2016** + +[Fixed](https://github.com/dfinke/ImportExcel/pull/126) PowerShell 3.0 compatibility. Thanks to [headsphere](https://github.com/headsphere). He used `$obj.PSObject.Methods[$target]` syntax to make it backward compatible. PS v4.0 and later allow `$obj.$target`. + +Thank you to [xelsirko](https://github.com/xelsirko) for fixing - _Import-module importexcel gives version warning if started inside background job_ + +**8/12/2016** + +[Fixed](https://github.com/dfinke/ImportExcel/issues/115) reading the headers from cells, moved from using `Text` property to `Value` property. + +**7/30/2016** + +* Added `Copy-ExcelWorksheet`. Let's you copy a work sheet from one Excel workbook to another. + +**7/21/2016** + +* Fixes `Import-Excel` \#68 + +**7/7/2016** + +[Attila Mihalicz](https://github.com/attilamihalicz) fixed two issues + +* Removing extra spaces after the backtick +* Uninitialized variable $idx leaks into the pipeline when `-TableName` parameter is used + +Thanks Attila. + +**7/1/2016** + +* Pushed 2.2.7 fixed resolve path in Get-ExcelSheetInfo +* Fixed [Casting Error in Export-Excel](https://github.com/dfinke/ImportExcel/issues/108) +* For `Import-Excel` change Resolve-Path to return ProviderPath for use with UNC + +**6/01/2016** + +* Added -UseDefaultCredentials to both `Import-Html` and `Get-HtmlTable` +* New functions, `Import-UPS` and `Import-USPS`. Pass in a valid tracking \# and it scrapes the page for the delivery details + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/Tracking.gif) + +**4/30/2016** + +Huge thank you to [Willie Möller](https://github.com/W1M0R) + +* He added a version check so the PowerShell Classes don't cause issues for down-level version of PowerShell +* He also contributed the first Pester tests for the module. Super! Check them out, they'll be the way tests will be implemented going forward + +**4/18/2016** + +Thanks to [Paul Williams](https://github.com/pauldalewilliams) for this feature. Now data can be transposed to columns for better charting. + +```text +$file = "C:\Temp\ps.xlsx" +rm $file -ErrorAction Ignore + +ps | + where company | + select Company,PagedMemorySize,PeakPagedMemorySize | + Export-Excel $file -Show -AutoSize ` + -IncludePivotTable ` + -IncludePivotChart ` + -ChartType ColumnClustered ` + -PivotRows Company ` + -PivotData @{PagedMemorySize='sum';PeakPagedMemorySize='sum'} +``` + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PivotAsRows.png) + +Add `-PivotDataToColumn` + +```text +$file = "C:\Temp\ps.xlsx" +rm $file -ErrorAction Ignore + +ps | + where company | + select Company,PagedMemorySize,PeakPagedMemorySize | + Export-Excel $file -Show -AutoSize ` + -IncludePivotTable ` + -IncludePivotChart ` + -ChartType ColumnClustered ` + -PivotRows Company ` + -PivotData @{PagedMemorySize='sum';PeakPagedMemorySize='sum'} ` + -PivotDataToColumn +``` + +And here is the new chart view ![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PivotAsColumns.png) + +**4/7/2016** + +Made more methods fluent + +```text +$t=Get-Range 0 5 .2 + +$t2=$t|%{$_*$_} +$t3=$t|%{$_*$_*$_} + +(New-Plot). + Plot($t,$t, $t,$t2, $t,$t3). + SetChartPosition("i"). + SetChartSize(500,500). + Title("Hello World"). + Show() +``` + +**3/31/2016** + +* Thanks to [redoz](https://github.com/redoz) Multi Series Charts are now working + +Also check out how you can create a table and then with Excel notation, index into the data for charting `"Impressions[A]"` + +```text +$data = @" +A,B,C,Date +2,1,1,2016-03-29 +5,10,1,2016-03-29 +"@ | ConvertFrom-Csv + +$c = New-ExcelChart -Title Impressions ` + -ChartType Line -Header "Something" ` + -XRange "Impressions[Date]" ` + -YRange @("Impressions[B]","Impressions[A]") + +$data | + Export-Excel temp.xlsx -AutoSize -TableName Impressions -Show -ExcelChartDefinition $c +``` + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/MultiSeries.gif) + +**3/26/2016** + +* Added `NumberFormat` parameter + +```text +$data | + Export-Excel -Path $file -Show -NumberFormat '[Blue]$#,##0.00;[Red]-$#,##0.00' +``` + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/Formatting.png) + +**3/18/2016** + +* Added `Get-Range`, `New-Plot` and Plot Cos example +* Updated EPPlus DLL. Allows markers to be changed and colored +* Handles and warns if auto name range names are also valid Excel ranges + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PSPlot.gif) + +**3/7/2016** + +* Added `Header` and `FirstDataRow` for `Import-Html` + +**3/2/2016** + +* Added `GreaterThan`, `GreaterThanOrEqual`, `LessThan`, `LessThanOrEqual` to `New-ConditionalText` + +```text +echo 489 668 299 777 860 151 119 497 234 788 | + Export-Excel c:\temp\test.xlsx -Show ` + -ConditionalText (New-ConditionalText -ConditionalType GreaterThan 525) +``` + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/GTConditional.png) + +**2/22/2016** + +* `Import-Html` using Lee Holmes [Extracting Tables from PowerShell’s Invoke-WebRequest](http://www.leeholmes.com/blog/2015/01/05/extracting-tables-from-PowerShells-invoke-webrequest/) + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/ImportHtml.gif) + +**2/17/2016** + +* Added Conditional Text types of `Equal` and `NotEqual` +* Phone \#'s like '+33 011 234 34' will be now be handled correctly + +### Try _PassThru_ + +```text +$file = "C:\Temp\passthru.xlsx" +rm $file -ErrorAction Ignore + +$xlPkg = $( + New-PSItem north 10 + New-PSItem east 20 + New-PSItem west 30 + New-PSItem south 40 +) | Export-Excel $file -PassThru + +$ws=$xlPkg.Workbook.Worksheets[1] + +$ws.Cells["A3"].Value = "Hello World" +$ws.Cells["B3"].Value = "Updating cells" +$ws.Cells["D1:D5"].Value = "Data" + +$ws.Cells.AutoFitColumns() + +$xlPkg.Save() +$xlPkg.Dispose() + +Invoke-Item $file +``` + +### Result + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PassThru.png) + +**1/18/2016** + +* Added `Conditional Text Formatting`. [Boe Prox](https://twitter.com/proxb) posted about [HTML Reporting, Part 2: Take Your Reporting a Step Further](https://mcpmag.com/articles/2016/01/14/html-reporting-part-2.aspx) and colorized cells. Great idea, now part of the PowerShell Excel module. + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/ConditionalText2.gif) + +**1/7/2016** + +* Added `Get-ExcelSheetInfo` - Great contribution from _Johan Åkerström_ check him out on [GitHub](https://github.com/CosmosKey) and [Twitter](https://twitter.com/neptune443) + +![](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/GetExcelSheetInfo.png) + +**12/26/2015** + +* Added `NoLegend`, `Show-Category`, `ShowPercent` for all charts including Pivot Charts +* Updated PieChart, BarChart, ColumnChart and Line chart to work with the pipeline and added `NoLegend`, `Show-Category`, `ShowPercent` + +**12/17/2015** + +These new features open the door for really sophisticated work sheet creation. + +Stay tuned for a [blog post](http://www.dougfinke.com/blog/) and examples. + +_**Quick List**_ + +* StartRow, StartColumn for placing data anywhere in a sheet +* New-ExcelChart - Add charts to a sheet, multiple series for a chart, locate the chart anywhere on the sheet +* AutoNameRange, Use functions and/or calculations in a cell +* Quick charting using PieChart, BarChart, ColumnChart and more + +![](https://raw.githubusercontent.com/dfinke/GifCam/master/JustCharts.gif) + +**10/20/2015** + +Big bug fix for version 3.0 PowerShell folks! + +This technique fails in 3.0 and works in 4.0 and later. + +```text +$m="substring" +"hello".$m(2,1) +``` + +Adding `.invoke` works in 3.0 and later. + +```text +$m="substring" +"hello".$m.invoke(2,1) +``` + +A _**big thank you**_ to [DarkLite1](https://github.com/DarkLite1) for adding the help to Export-Excel. + +Added `-HeaderRow` parameter. Sometimes the heading does not start in Row 1. + +**10/16/2015** + +Fixes [Export-Excel generates corrupt Excel file](https://github.com/dfinke/ImportExcel/issues/46) + +**10/15/2015** + +`Import-Excel` has a new parameter `NoHeader`. If data in the sheet does not have headers and you don't want to supply your own, `Import-Excel` will generate the property name. + +`Import-Excel` now returns `.Value` rather than `.Text` + +**10/1/2015** + +Merged ValidateSet for Encoding and Extension. Thank you [Irwin Strachan](https://github.com/irwins). + +**9/30/2015** + +Export-Excel can now handle data that is **not** an object + +```text +echo a b c 1 $true 2.1 1/1/2015 | Export-Excel c:\temp\test.xlsx -Show +``` + +Or + +```text +dir -Name | Export-Excel c:\temp\test.xlsx -Show +``` + +**9/25/2015** + +**Hide worksheets** Got a great request from [forensicsguy20012004](https://github.com/forensicsguy20012004) to hide worksheets. You create a few pivotables, generate charts and then pivot table worksheets don't need to be visible. + +`Export-Excel` now has a `-HideSheet` parameter that takes and array of worksheet names and hides them. + +**Example** + +Here, you create four worksheets named `PM`,`Handles`,`Services` and `Files`. + +The last line creates the `Files` sheet and then hides the `Handles`,`Services` sheets. + +```text +$p = Get-Process + +$p|select company, pm | Export-Excel $xlFile -WorkSheetname PM +$p|select company, handles| Export-Excel $xlFile -WorkSheetname Handles +Get-Service| Export-Excel $xlFile -WorkSheetname Services + +dir -File | Export-Excel $xlFile -WorkSheetname Files -Show -HideSheet Handles, Services +``` + +**Note** There is a bug in EPPlus that does not let you hide the first worksheet created. Hopefully it'll resolved soon. + +**9/11/2015** + +Added Conditional formatting. See [TryConditional.ps1](https://github.com/dfinke/ImportExcel/blob/master/TryConditional.ps1) as an example. + +Or, check out the short _**"How To"**_ video. + +[![image](http://www.dougfinke.com/videos/excelpsmodule/ExcelPSModule_First_Frame.png)](http://www.dougfinke.com/videos/excelpsmodule/excelpsmodule.mp4) + +**8/21/2015** + +* Now import Excel sheets even if the file is open in Excel. Thank you [Francois Lachance-Guillemette](https://github.com/francoislg) + +**7/09/2015** + +* For -PivotRows you can pass a `hashtable` with the name of the property and the type of calculation. `Sum`, `Average`, `Max`, `Min`, `Product`, `StdDev`, `StdDevp`, `Var`, `Varp` + +```text +Get-Service | + Export-Excel "c:\temp\test.xlsx" ` + -Show ` + -IncludePivotTable ` + -PivotRows status ` + -PivotData @{status='count'} +``` + +**6/16/2015 \(Thanks Justin\)** + +* Improvements to PivotTable overwriting +* Added two parameters to Export-Excel + * RangeName - Turns the data piped to Export-Excel into a named range. + * TableName - Turns the data piped to Export-Excel into an excel table. + +Examples + +```text +Get-Process|Export-Excel foo.xlsx -Verbose -IncludePivotTable -TableName "Processes" -Show +Get-Process|Export-Excel foo.xlsx -Verbose -IncludePivotTable -RangeName "Processes" -Show +``` + +**5/25/2015** + +* Fixed null header problem + +**5/17/2015** + +* Added three parameters: + * FreezeTopRow - Freezes the first row of the data + * AutoFilter - Enables filtering for the data in the sheet + * BoldTopRow - Bolds the top row of data, the column headers + +Example + +```text +Get-CimInstance win32_service | + select state, accept*, start*, caption | + Export-Excel test.xlsx -Show -BoldTopRow -AutoFilter -FreezeTopRow -AutoSize +``` + +![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/FilterFreezeBold.gif) + +**5/4/2015** + +* Published to PowerShell Gallery. In PowerShell v5 use `Find-Module importexcel` then `Find-Module importexcel | Install-Module` + +**4/27/2015** + +* datetime properties were displaying as ints, now are formatted + +**4/25/2015** + +* Now you can create multiple Pivot tables in one pass + * Thanks to [pscookiemonster](https://twitter.com/pscookiemonster), he submitted a repro case to the EPPlus CodePlex project and got it fixed + +**Example** + +```text +$ps = ps + +$ps | + Export-Excel .\testExport.xlsx -WorkSheetname memory ` + -IncludePivotTable -PivotRows Company -PivotData PM ` + -IncludePivotChart -ChartType PieExploded3D +$ps | + Export-Excel .\testExport.xlsx -WorkSheetname handles ` + -IncludePivotTable -PivotRows Company -PivotData Handles ` + -IncludePivotChart -ChartType PieExploded3D -Show +``` + +![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/MultiplePivotTables.png) + +**4/20/2015** + +* Included and embellished [Claus Nielsen](https://github.com/Claustn) function to take all sheets in an Excel file workbook and create a text file for each `ConvertFrom-ExcelSheet` +* Renamed `Export-MultipleExcelSheets` to `ConvertFrom-ExcelSheet` + +**4/13/2015** + +* You can add a title to the Excel "Report" `Title`, `TitleFillPattern`, `TitleBold`, `TitleSize`, `TitleBackgroundColor` + * Thanks to [Irwin Strachan](http://pshirwin.wordpress.com) for this and other great suggestions, testing and more + +**4/10/2015** + +* Renamed `AutoFitColumns` to `AutoSize` +* Implemented `Export-MultipleExcelSheets` +* Implemented `-Password` for a worksheet +* Replaced `-Force` switch with `-NoClobber` switch +* Added examples for `Get-Help` +* If Pivot table is requested, that sheet becomes the tab selected + +**4/8/2015** + +* Implemented exporting data to **named sheets** via the -WorkSheetname parameter. + +Examples - `gsv | Export-Excel .\test.xlsx -WorkSheetname Services` + +`dir -file | Export-Excel .\test.xlsx -WorkSheetname Files` + +`ps | Export-Excel .\test.xlsx -WorkSheetname Processes -IncludePivotTable -Show -PivotRows Company -PivotData PM` + +**Convert \(All or Some\) Excel Sheets to Text files** + +Reads each sheet in TestSheets.xlsx and outputs it to the data directory as the sheet name with the extension .txt + +```text +ConvertFrom-ExcelSheet .\TestSheets.xlsx .\data +``` + +Reads and outputs sheets like Sheet10 and Sheet20 form TestSheets.xlsx and outputs it to the data directory as the sheet name with the extension .txt + +```text +ConvertFrom-ExcelSheet .\TestSheets.xlsx .\data sheet?0 +``` + +**Example Adding a Title** + +You can set the pattern, size and of if the title is bold. + +```text +$p=@{ + Title = "Process Report as of $(Get-Date)" + TitleFillPattern = "LightTrellis" + TitleSize = 18 + TitleBold = $true + + Path = "$pwd\testExport.xlsx" + Show = $true + AutoSize = $true +} + +Get-Process | + Where Company | Select Company, PM | + Export-Excel @p +``` + +![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/Title.png) + +**Example Export-MultipleExcelSheets** + +![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/ExportMultiple.gif) + +```text +$p = Get-Process + +$DataToGather = @{ + PM = {$p|select company, pm} + Handles = {$p|select company, handles} + Services = {gsv} + Files = {dir -File} + Albums = {(Invoke-RestMethod http://www.dougfinke.com/PowerShellfordevelopers/albums.js)} +} + +Export-MultipleExcelSheets -Show -AutoSize .\testExport.xlsx $DataToGather +``` + +_**NOTE**_ If the sheet exists when using _-WorkSheetname_ parameter, it will be deleted and then added with the new data. + +### Get-Process Exported to Excel + +#### Total Physical Memory Grouped By Company + +![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/PivotTablesAndCharts.png) + +### Importing data from an Excel spreadsheet + +![image](https://raw.githubusercontent.com/dfinke/ImportExcel/master/images/TryImportExcel.gif) + +You can also find EPPLus on [Nuget](https://www.nuget.org/packages/EPPlus/). + +### Known Issues + +* Using `-IncludePivotTable`, if that pivot table name exists, you'll get an error. + * Investigating a solution + * _Workaround_ delete the Excel file first, then do the export + From 8c6c7eeaf65747e49b5c4936037edd41b59c25cf Mon Sep 17 00:00:00 2001 From: Doug Finke Date: Sat, 7 May 2022 17:15:24 -0400 Subject: [PATCH 137/140] update --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 063339e..38e01fb 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ Quickly read a spreadsheet document into a PowerShell array. ```powershell $data = Import-Excel .\salesData.xlsx + +$data ``` ```powershell From e2053e499821771a937571fe009a8105ba8714f4 Mon Sep 17 00:00:00 2001 From: Doug Finke Date: Sat, 7 May 2022 17:19:15 -0400 Subject: [PATCH 138/140] fix casing --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38e01fb..4a3b951 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ $chart = New-ExcelChartDefinition -XRange State -YRange Units -Title "Units by S $data | Export-Excel .\salesData.xlsx -AutoNameRange -ExcelChartDefinition $chart -Show ``` -![](images/salesDataChart.png) +![](images/SalesDataChart.png) ## Add a pivot table to spreadsheet From d5b807d3cb36701040f8c192660e2754d72c4ebf Mon Sep 17 00:00:00 2001 From: dfinke Date: Sat, 28 May 2022 06:32:01 -0400 Subject: [PATCH 139/140] Don't publish images folder and more - Suggestion: Remove unnecessary files when publishing to the gallery #1187 --- ImportExcel.psd1 | 7 +++---- InstallModule.ps1 | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ImportExcel.psd1 b/ImportExcel.psd1 index d47e882..ccad95c 100644 --- a/ImportExcel.psd1 +++ b/ImportExcel.psd1 @@ -6,7 +6,7 @@ RootModule = 'ImportExcel.psm1' # Version number of this module. - ModuleVersion = '7.5.2' + ModuleVersion = '7.5.3' # ID used to uniquely identify this module GUID = '60dd4136-feff-401a-ba27-a84458c57ede' @@ -131,9 +131,8 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5 '.\Charting\Charting.ps1', '.\InferData\InferData.ps1', '.\Pivot\Pivot.ps1', - '.\spikes\ConvertFrom-ExcelColumnName.ps1', - '.\Examples', '.\images', '.\Testimonials' - + '.\Examples', + '.\Testimonials' ) # Private data to pass to the module specified in RootModule/ModuleToProcess diff --git a/InstallModule.ps1 b/InstallModule.ps1 index ac08d1e..0e006b1 100644 --- a/InstallModule.ps1 +++ b/InstallModule.ps1 @@ -7,5 +7,5 @@ if (-not $fullPath) { $fullPath = Join-Path $fullPath -ChildPath "ImportExcel" } Push-location $PSScriptRoot -Robocopy . $fullPath /mir /XD .vscode .git CI __tests__ data mdHelp /XF appveyor.yml azure-pipelines.yml .gitattributes .gitignore filelist.txt install.ps1 InstallModule.ps1 +Robocopy . $fullPath /mir /XD .vscode images .git .github CI __tests__ data mdHelp spikes /XF README.md README.original.md appveyor.yml azure-pipelines.yml .gitattributes .gitignore filelist.txt install.ps1 InstallModule.ps1 PublishToGallery.ps1 Pop-Location \ No newline at end of file From 8bb3d500527808f1d191cc442458ae150cd9d572 Mon Sep 17 00:00:00 2001 From: dfinke Date: Sun, 29 May 2022 09:54:02 -0400 Subject: [PATCH 140/140] Add sample - How to convert abbreviate or shorten long numbers in Excel --- Examples/CustomNumbers/ShortenNumbers.ps1 | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Examples/CustomNumbers/ShortenNumbers.ps1 diff --git a/Examples/CustomNumbers/ShortenNumbers.ps1 b/Examples/CustomNumbers/ShortenNumbers.ps1 new file mode 100644 index 0000000..1484d3a --- /dev/null +++ b/Examples/CustomNumbers/ShortenNumbers.ps1 @@ -0,0 +1,23 @@ +# How to convert abbreviate or shorten long numbers in Excel + +Remove-Item .\custom.xlsx -ErrorAction SilentlyContinue + +$data = $( + 12000 + 1000 + 2000 + 3000 + 2400 + 3600 + 6000 + 13000 + 40000 + 400000 + 1000000 +) + +$excel = $data | Export-Excel .\custom.xlsx -PassThru + +Set-ExcelRange -Worksheet $excel.Sheet1 -Range "A:A" -NumberFormat '[>999999]#,,"M";#,"K"' + +Close-ExcelPackage $excel -Show \ No newline at end of file