mirror of
https://github.com/dfinke/ImportExcel.git
synced 2025-12-27 13:43:36 +00:00
Compare commits
13 Commits
e1e4cfd02e
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5040fc0542 | ||
|
|
f62aff64db | ||
|
|
bc289afc6b | ||
|
|
5387c06146 | ||
|
|
45ed6a06dc | ||
|
|
fa447a745c | ||
|
|
49affcfba7 | ||
|
|
dc4a5e9db9 | ||
|
|
85e48acf36 | ||
|
|
fb41d3de83 | ||
|
|
db84a59dd0 | ||
|
|
5a61c5dda4 | ||
|
|
a2bc50aeb0 |
@@ -6,7 +6,7 @@
|
||||
RootModule = 'ImportExcel.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '7.8.9'
|
||||
ModuleVersion = '7.8.10'
|
||||
|
||||
# ID used to uniquely identify this module
|
||||
GUID = '60dd4136-feff-401a-ba27-a84458c57ede'
|
||||
@@ -150,7 +150,7 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5
|
||||
Tags = @("Excel", "EPPlus", "Export", "Import")
|
||||
|
||||
# The web address of an icon which can be used in galleries to represent this module
|
||||
#IconUri = "http://pesterbdd.com/images/Pester.png"
|
||||
#IconUri =
|
||||
|
||||
# The web address of this module's project or support homepage.
|
||||
ProjectUri = "https://github.com/dfinke/ImportExcel"
|
||||
@@ -215,4 +215,4 @@ Check out the How To Videos https://www.youtube.com/watch?v=U3Ne_yX4tYo&list=PL5
|
||||
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
|
||||
# DefaultCommandPrefix = ''
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ function Close-ExcelPackage {
|
||||
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." }
|
||||
}
|
||||
# Set FullCalcOnLoad to false to prevent Excel from corrupting formulas during recalculation
|
||||
# This fixes issues with table-structured references like [[#This Row],[ColumnName]]
|
||||
$ExcelPackage.Workbook.FullCalcOnLoad = $false
|
||||
if ($SaveAs) {
|
||||
$SaveAs = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($SaveAs)
|
||||
if ($Password) { $ExcelPackage.SaveAs( $SaveAs, $Password ) }
|
||||
|
||||
@@ -3,76 +3,60 @@ function ConvertTo-ExcelXlsx {
|
||||
param
|
||||
(
|
||||
[parameter(Mandatory = $true, ValueFromPipeline)]
|
||||
[string[]]$Path,
|
||||
[string]$Path,
|
||||
[parameter(Mandatory = $false)]
|
||||
[switch]$Force
|
||||
)
|
||||
process {
|
||||
try {
|
||||
foreach ($singlePath in $Path) {
|
||||
if (-Not ($singlePath | Test-Path) ) {
|
||||
throw "File not found"
|
||||
}
|
||||
if (-Not ($singlePath | Test-Path -PathType Leaf) ) {
|
||||
throw "Folder paths are not allowed"
|
||||
}
|
||||
if (-Not ($Path | Test-Path) ) {
|
||||
throw "File not found"
|
||||
}
|
||||
if (-Not ($Path | Test-Path -PathType Leaf) ) {
|
||||
throw "Folder paths are not allowed"
|
||||
}
|
||||
|
||||
$xlFixedFormat = 51 #Constant for XLSX Workbook
|
||||
$xlsFile = Get-Item -Path $singlePath
|
||||
$xlsxPath = [System.IO.Path]::ChangeExtension($xlsFile.FullName, ".xlsx")
|
||||
$xlFixedFormat = 51 #Constant for XLSX Workbook
|
||||
$xlsFile = Get-Item -Path $Path
|
||||
$xlsxPath = "{0}x" -f $xlsFile.FullName
|
||||
|
||||
if ($xlsFile.Extension -ne ".xls") {
|
||||
throw "Expected .xls extension"
|
||||
}
|
||||
if ($xlsFile.Extension -ne ".xls") {
|
||||
throw "Expected .xls extension"
|
||||
}
|
||||
|
||||
if (Test-Path -Path $xlsxPath) {
|
||||
if ($Force) {
|
||||
try {
|
||||
Remove-Item $xlsxPath -Force
|
||||
}
|
||||
catch {
|
||||
throw "{0} already exists and cannot be removed. The file may be locked by another application." -f $xlsxPath
|
||||
}
|
||||
Write-Verbose $("Removed {0}" -f $xlsxPath)
|
||||
}
|
||||
else {
|
||||
throw "{0} already exists!" -f $xlsxPath
|
||||
}
|
||||
}
|
||||
|
||||
if ($null -eq $Excel)
|
||||
{
|
||||
try {
|
||||
$Excel = New-Object -ComObject "Excel.Application"
|
||||
}
|
||||
catch {
|
||||
throw "Could not create Excel.Application ComObject. Please verify that Excel is installed."
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$Excel.Visible = $false
|
||||
$workbook = $Excel.Workbooks.Open($xlsFile.FullName, $null, $true)
|
||||
if ($null -eq $workbook) {
|
||||
Write-Host "Failed to open workbook"
|
||||
} else {
|
||||
$workbook.SaveAs($xlsxPath, $xlFixedFormat)
|
||||
}
|
||||
if (Test-Path -Path $xlsxPath) {
|
||||
if ($Force) {
|
||||
try {
|
||||
Remove-Item $xlsxPath -Force
|
||||
}
|
||||
catch {
|
||||
Write-Error ("Failed to convert {0} to XLSX." -f $xlsFile.FullName)
|
||||
throw
|
||||
}
|
||||
finally {
|
||||
if ($null -ne $workbook) {
|
||||
$workbook.Close()
|
||||
}
|
||||
throw "{0} already exists and cannot be removed. The file may be locked by another application." -f $xlsxPath
|
||||
}
|
||||
Write-Verbose $("Removed {0}" -f $xlsxPath)
|
||||
}
|
||||
else {
|
||||
throw "{0} already exists!" -f $xlsxPath
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$Excel = New-Object -ComObject "Excel.Application"
|
||||
}
|
||||
catch {
|
||||
throw "Could not create Excel.Application ComObject. Please verify that Excel is installed."
|
||||
}
|
||||
|
||||
try {
|
||||
$Excel.Visible = $false
|
||||
$null = $Excel.Workbooks.Open($xlsFile.FullName, $null, $true)
|
||||
$Excel.ActiveWorkbook.SaveAs($xlsxPath, $xlFixedFormat)
|
||||
}
|
||||
finally {
|
||||
if ($null -ne $Excel.ActiveWorkbook) {
|
||||
$Excel.ActiveWorkbook.Close()
|
||||
}
|
||||
|
||||
$Excel.Quit()
|
||||
$Excel = $null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -682,6 +682,9 @@
|
||||
else {
|
||||
if ($ReturnRange) { $dataRange }
|
||||
|
||||
# Set FullCalcOnLoad to false to prevent Excel from corrupting formulas during recalculation
|
||||
# This fixes issues with table-structured references like [[#This Row],[ColumnName]]
|
||||
$pkg.Workbook.FullCalcOnLoad = $false
|
||||
if ($Password) { $pkg.Save($Password) }
|
||||
else { $pkg.Save() }
|
||||
Write-Verbose -Message "Saved workbook $($pkg.File)"
|
||||
|
||||
@@ -50,7 +50,9 @@ function Get-HtmlTable {
|
||||
else {
|
||||
$h = ConvertFrom-Html -Content $r.Content
|
||||
if ($TableIndex -is [valuetype]) { $TableIndex += 1}
|
||||
$rows = $h.SelectNodes("//table[$TableIndex]//tr")
|
||||
$rows = try {
|
||||
$h.SelectSingleNode("//table[$TableIndex]").SelectNodes(".//tr")
|
||||
} catch {}
|
||||
if (-not $rows) {Write-Warning "Could not find rows for `"//table[$TableIndex]`" in $Url ."}
|
||||
if ( -not $propertyNames) {
|
||||
if ( $tableHeaders = $rows[$FirstDataRow].SelectNodes("th")) {
|
||||
|
||||
125
__tests__/TableFormula.tests.ps1
Normal file
125
__tests__/TableFormula.tests.ps1
Normal file
@@ -0,0 +1,125 @@
|
||||
#Requires -Modules @{ ModuleName="Pester"; ModuleVersion="4.0.0" }
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'False Positives')]
|
||||
param()
|
||||
|
||||
Describe "Table Formula Bug Fix" -Tag "TableFormula" {
|
||||
BeforeAll {
|
||||
$WarningAction = "SilentlyContinue"
|
||||
}
|
||||
|
||||
Context "FullCalcOnLoad is set to false to prevent formula corruption" {
|
||||
BeforeAll {
|
||||
$path = "TestDrive:\table_formula.xlsx"
|
||||
Remove-Item -Path $path -ErrorAction SilentlyContinue
|
||||
|
||||
# Create a table with a blank record
|
||||
$BlankRecordForFile = [PsCustomObject]@{
|
||||
'Action Add' = ''
|
||||
UserName = ''
|
||||
Address = ''
|
||||
Name = ''
|
||||
NewName = ''
|
||||
}
|
||||
|
||||
# Export as a table
|
||||
$ExcelFile = $BlankRecordForFile | Export-Excel -Path $path -WorksheetName 'Data' `
|
||||
-TableName 'DataTable' -TableStyle 'Light1' -AutoSize:$false -AutoFilter `
|
||||
-BoldTopRow -FreezeTopRow -StartRow 1 -PassThru
|
||||
|
||||
$Worksheet = $ExcelFile.Workbook.Worksheets['Data']
|
||||
|
||||
# Insert a row and add a complex formula with table-structured references
|
||||
$Worksheet.InsertRow(2, 1)
|
||||
|
||||
# This formula uses old-style table references [[#This Row],[ColumnName]]
|
||||
# which Excel converts to [@ColumnName] when opening
|
||||
$Formula = '=IFS( [[#This Row],[UserName]]="","", [[#This Row],[Action Add]]=TRUE, CONCAT([[#This Row],[Address]],"-",[[#This Row],[UserName]]), CONCAT([[#This Row],[Address]],"-",[[#This Row],[UserName]]) <> [[#This Row],[Name]], CONCAT([[#This Row],[Address]],"-",[[#This Row],[UserName]]), TRUE, "")'
|
||||
|
||||
$Cell = $Worksheet.Cells['e2']
|
||||
$Cell.Formula = $Formula
|
||||
|
||||
Close-ExcelPackage $ExcelFile
|
||||
|
||||
# Reopen to verify
|
||||
$ExcelFile2 = Open-ExcelPackage -Path $path
|
||||
$Worksheet2 = $ExcelFile2.Workbook.Worksheets['Data']
|
||||
}
|
||||
|
||||
It "Sets fullCalcOnLoad to false in the workbook XML" {
|
||||
# Extract and check the XML directly
|
||||
$TempExtractPath = Join-Path -Path $TestDrive -ChildPath "extracted_$(Get-Random)"
|
||||
Expand-Archive -Path $path -DestinationPath $TempExtractPath -Force
|
||||
$WorkbookXml = Get-Content (Join-Path -Path $TempExtractPath -ChildPath "xl/workbook.xml") -Raw
|
||||
|
||||
$WorkbookXml | Should -Match 'fullCalcOnLoad="0"'
|
||||
|
||||
Remove-Item -Path $TempExtractPath -Recurse -Force
|
||||
}
|
||||
|
||||
It "Preserves the formula correctly after save and reopen" {
|
||||
$Cell2 = $Worksheet2.Cells['e2']
|
||||
$Cell2.Formula | Should -Not -BeNullOrEmpty
|
||||
$Cell2.Formula | Should -Match 'IFS\('
|
||||
$Cell2.Formula | Should -Match 'CONCAT\('
|
||||
}
|
||||
|
||||
It "Does not corrupt the formula with extra @ symbols" {
|
||||
$Cell2 = $Worksheet2.Cells['e2']
|
||||
# The formula should not have extra @ symbols added by Excel during recalculation
|
||||
# The specific bug was an @ being inserted before CONCAT in the middle of the formula
|
||||
# We can't test this directly without opening in Excel, but we can verify the formula is unchanged
|
||||
$Cell2.Formula.Length | Should -BeGreaterThan 100
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
if ($ExcelFile2) {
|
||||
Close-ExcelPackage -ExcelPackage $ExcelFile2 -NoSave
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "FullCalcOnLoad setting works with different save methods" {
|
||||
It "Sets fullCalcOnLoad to false when using SaveAs" {
|
||||
$path = "TestDrive:\saveas_test.xlsx"
|
||||
$path2 = "TestDrive:\saveas_test2.xlsx"
|
||||
Remove-Item -Path $path, $path2 -ErrorAction SilentlyContinue
|
||||
|
||||
$data = [PSCustomObject]@{ Name = 'Test' }
|
||||
$excel = $data | Export-Excel -Path $path -PassThru
|
||||
|
||||
Close-ExcelPackage $excel -SaveAs $path2
|
||||
|
||||
# Extract and check the XML
|
||||
$TempExtractPath = Join-Path -Path $TestDrive -ChildPath "extracted_saveas_$(Get-Random)"
|
||||
Expand-Archive -Path $path2 -DestinationPath $TempExtractPath -Force
|
||||
$WorkbookXml = Get-Content (Join-Path -Path $TempExtractPath -ChildPath "xl/workbook.xml") -Raw
|
||||
|
||||
$WorkbookXml | Should -Match 'fullCalcOnLoad="0"'
|
||||
|
||||
Remove-Item -Path $TempExtractPath -Recurse -Force
|
||||
}
|
||||
|
||||
It "Sets fullCalcOnLoad to false when using Calculate flag" {
|
||||
$path = "TestDrive:\calculate_test.xlsx"
|
||||
Remove-Item -Path $path -ErrorAction SilentlyContinue
|
||||
|
||||
$data = [PSCustomObject]@{ Name = 'Test'; Value = 100 }
|
||||
$excel = $data | Export-Excel -Path $path -PassThru
|
||||
|
||||
# Set a formula
|
||||
$ws = $excel.Workbook.Worksheets[1]
|
||||
$ws.Cells['C2'].Formula = 'B2*2'
|
||||
|
||||
Close-ExcelPackage $excel -Calculate
|
||||
|
||||
# Extract and check the XML
|
||||
$TempExtractPath = Join-Path -Path $TestDrive -ChildPath "extracted_calc_$(Get-Random)"
|
||||
Expand-Archive -Path $path -DestinationPath $TempExtractPath -Force
|
||||
$WorkbookXml = Get-Content (Join-Path -Path $TempExtractPath -ChildPath "xl/workbook.xml") -Raw
|
||||
|
||||
$WorkbookXml | Should -Match 'fullCalcOnLoad="0"'
|
||||
|
||||
Remove-Item -Path $TempExtractPath -Recurse -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
# 7.8.10
|
||||
|
||||
- Thank you https://github.com/evenmartinsen for the PR to fix the AV
|
||||
|
||||
# 7.8.9
|
||||
|
||||
- Thanks to (Edward Miller)[https://github.com/edwardmiller-mesirow] for improving `ConvertTo-ExcelXlsx`and making it more robust
|
||||
|
||||
5592
llms-examples.txt
Normal file
5592
llms-examples.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user