From 66c0fee1e9d5349a8f8be2b3ab02ad93f5d98794 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Tue, 21 May 2024 15:56:53 -0500 Subject: [PATCH 1/7] Prevent error: "Unable to get the SaveAs property of the Workbook class" --- Public/ConvertTo-ExcelXlsx.ps1 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Public/ConvertTo-ExcelXlsx.ps1 b/Public/ConvertTo-ExcelXlsx.ps1 index 578445e0..06094e71 100644 --- a/Public/ConvertTo-ExcelXlsx.ps1 +++ b/Public/ConvertTo-ExcelXlsx.ps1 @@ -47,12 +47,16 @@ function ConvertTo-ExcelXlsx { try { $Excel.Visible = $false - $null = $Excel.Workbooks.Open($xlsFile.FullName, $null, $true) - $Excel.ActiveWorkbook.SaveAs($xlsxPath, $xlFixedFormat) + $workbook = $Excel.Workbooks.Open($xlsFile.FullName, $null, $true) + if ($null -eq $workbook) { + Write-Host "Failed to open workbook" + } else { + $workbook.SaveAs($xlsxPath, $xlFixedFormat) + } } finally { - if ($null -ne $Excel.ActiveWorkbook) { - $Excel.ActiveWorkbook.Close() + if ($null -ne $workbook) { + $workbook.Close() } $Excel.Quit() From 88a3aac640383dac2eec697300cd94fb646b3e6f Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Tue, 21 May 2024 16:38:53 -0500 Subject: [PATCH 2/7] accept a collection of paths --- Public/ConvertTo-ExcelXlsx.ps1 | 105 +++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 44 deletions(-) diff --git a/Public/ConvertTo-ExcelXlsx.ps1 b/Public/ConvertTo-ExcelXlsx.ps1 index 06094e71..f1150752 100644 --- a/Public/ConvertTo-ExcelXlsx.ps1 +++ b/Public/ConvertTo-ExcelXlsx.ps1 @@ -3,64 +3,81 @@ function ConvertTo-ExcelXlsx { param ( [parameter(Mandatory = $true, ValueFromPipeline)] - [string]$Path, + [string[]]$Path, [parameter(Mandatory = $false)] [switch]$Force ) process { - if (-Not ($Path | Test-Path) ) { - throw "File not found" - } - if (-Not ($Path | Test-Path -PathType Leaf) ) { - throw "Folder paths are not allowed" - } + 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" + } - $xlFixedFormat = 51 #Constant for XLSX Workbook - $xlsFile = Get-Item -Path $Path - $xlsxPath = "{0}x" -f $xlsFile.FullName + $xlFixedFormat = 51 #Constant for XLSX Workbook + $xlsFile = Get-Item -Path $singlePath + $xlsxPath = "{0}x" -f $xlsFile.FullName - if ($xlsFile.Extension -ne ".xls") { - throw "Expected .xls extension" - } - - if (Test-Path -Path $xlsxPath) { - if ($Force) { - try { - Remove-Item $xlsxPath -Force + if ($xlsFile.Extension -ne ".xls") { + throw "Expected .xls extension" } - catch { - throw "{0} already exists and cannot be removed. The file may be locked by another application." -f $xlsxPath + + 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 + } } - 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." - } + 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) + 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) + } + } + catch { + Write-Error ("Failed to convert {0} to XLSX." -f $xlsFile.FullName) + throw + } + finally { + if ($null -ne $workbook) { + $workbook.Close() + [System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook) | Out-Null + $workbook = $null + } + } } } finally { - if ($null -ne $workbook) { - $workbook.Close() + if ($null -ne $Excel) { + $Excel.Quit() + [System.Runtime.InteropServices.Marshal]::ReleaseComObject($Excel) | Out-Null + $Excel = $null } - - $Excel.Quit() } } } - From b6034c37d80d44f336451cb557fece9d28f86b1d Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Tue, 21 May 2024 16:38:56 -0500 Subject: [PATCH 3/7] use ChangeExtension for robustness --- Public/ConvertTo-ExcelXlsx.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Public/ConvertTo-ExcelXlsx.ps1 b/Public/ConvertTo-ExcelXlsx.ps1 index f1150752..354282bc 100644 --- a/Public/ConvertTo-ExcelXlsx.ps1 +++ b/Public/ConvertTo-ExcelXlsx.ps1 @@ -19,7 +19,7 @@ function ConvertTo-ExcelXlsx { $xlFixedFormat = 51 #Constant for XLSX Workbook $xlsFile = Get-Item -Path $singlePath - $xlsxPath = "{0}x" -f $xlsFile.FullName + $xlsxPath = [System.IO.Path]::ChangeExtension($xlsFile.FullName, ".xlsx") if ($xlsFile.Extension -ne ".xls") { throw "Expected .xls extension" From 37cd7335c7a67bc01ffd8934d951af3f5bda1135 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Wed, 22 May 2024 10:32:18 -0500 Subject: [PATCH 4/7] optionally cache to temp file to avoid locking issues --- Public/ConvertTo-ExcelXlsx.ps1 | 38 +++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/Public/ConvertTo-ExcelXlsx.ps1 b/Public/ConvertTo-ExcelXlsx.ps1 index 354282bc..75b7362a 100644 --- a/Public/ConvertTo-ExcelXlsx.ps1 +++ b/Public/ConvertTo-ExcelXlsx.ps1 @@ -5,7 +5,9 @@ function ConvertTo-ExcelXlsx { [parameter(Mandatory = $true, ValueFromPipeline)] [string[]]$Path, [parameter(Mandatory = $false)] - [switch]$Force + [switch]$Force, + [parameter(Mandatory = $false)] + [switch]$CacheToTemp ) process { try { @@ -19,24 +21,24 @@ function ConvertTo-ExcelXlsx { $xlFixedFormat = 51 #Constant for XLSX Workbook $xlsFile = Get-Item -Path $singlePath - $xlsxPath = [System.IO.Path]::ChangeExtension($xlsFile.FullName, ".xlsx") + $destinationXlsxPath = [System.IO.Path]::ChangeExtension($xlsFile.FullName, ".xlsx") if ($xlsFile.Extension -ne ".xls") { throw "Expected .xls extension" } - if (Test-Path -Path $xlsxPath) { + if (Test-Path -Path $destinationXlsxPath) { if ($Force) { try { - Remove-Item $xlsxPath -Force + Remove-Item $destinationXlsxPath -Force } catch { - throw "{0} already exists and cannot be removed. The file may be locked by another application." -f $xlsxPath + throw "{0} already exists and cannot be removed. The file may be locked by another application." -f $destinationXlsxPath } - Write-Verbose $("Removed {0}" -f $xlsxPath) + Write-Verbose $("Removed {0}" -f $destinationXlsxPath) } else { - throw "{0} already exists!" -f $xlsxPath + throw "{0} already exists!" -f $destinationXlsxPath } } @@ -50,13 +52,28 @@ function ConvertTo-ExcelXlsx { } } + if ($CacheToTemp) { + $tempPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetFileName($xlsFile.FullName)) + Copy-Item -Path $xlsFile.FullName -Destination $tempPath -Force + $fileToProcess = $tempPath + } + else { + $fileToProcess = $xlsFile.FullName + } + + $xlsxPath = [System.IO.Path]::ChangeExtension($fileToProcess, ".xlsx") + try { $Excel.Visible = $false - $workbook = $Excel.Workbooks.Open($xlsFile.FullName, $null, $true) + $workbook = $Excel.Workbooks.Open($fileToProcess, $null, $true) if ($null -eq $workbook) { Write-Host "Failed to open workbook" } else { $workbook.SaveAs($xlsxPath, $xlFixedFormat) + + if ($CacheToTemp) { + Copy-Item -Path $xlsxPath -Destination $destinationXlsxPath -Force + } } } catch { @@ -69,6 +86,11 @@ function ConvertTo-ExcelXlsx { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook) | Out-Null $workbook = $null } + + if ($CacheToTemp) { + Remove-Item -Path $tempPath -Force + Remove-Item -Path $xlsxPath -Force + } } } } From 34c30eb30174c6d02db76957ca45e6cb7d289651 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Wed, 22 May 2024 13:38:30 -0500 Subject: [PATCH 5/7] allow configuring cache directory --- Public/ConvertTo-ExcelXlsx.ps1 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Public/ConvertTo-ExcelXlsx.ps1 b/Public/ConvertTo-ExcelXlsx.ps1 index 75b7362a..b301089d 100644 --- a/Public/ConvertTo-ExcelXlsx.ps1 +++ b/Public/ConvertTo-ExcelXlsx.ps1 @@ -7,7 +7,9 @@ function ConvertTo-ExcelXlsx { [parameter(Mandatory = $false)] [switch]$Force, [parameter(Mandatory = $false)] - [switch]$CacheToTemp + [switch]$CacheToTemp, + [parameter(Mandatory = $false)] + [string]$CacheDirectory ) process { try { @@ -53,7 +55,11 @@ function ConvertTo-ExcelXlsx { } if ($CacheToTemp) { - $tempPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetFileName($xlsFile.FullName)) + if (-not $CacheDirectory) { + $CacheDirectory = [System.IO.Path]::GetTempPath() + } + $tempPath = [System.IO.Path]::Combine($CacheDirectory, [System.IO.Path]::GetFileName($xlsFile.FullName)) + Write-Host ("Using Temp path: {0}" -f $tempPath) Copy-Item -Path $xlsFile.FullName -Destination $tempPath -Force $fileToProcess = $tempPath } From 5096aa2a0e49fdf568ea420ccf4830e2f23e476c Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Fri, 21 Jun 2024 01:03:39 -0500 Subject: [PATCH 6/7] add helpful hint for users who experience errors --- Public/ConvertTo-ExcelXlsx.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Public/ConvertTo-ExcelXlsx.ps1 b/Public/ConvertTo-ExcelXlsx.ps1 index b301089d..e911a536 100644 --- a/Public/ConvertTo-ExcelXlsx.ps1 +++ b/Public/ConvertTo-ExcelXlsx.ps1 @@ -83,7 +83,7 @@ function ConvertTo-ExcelXlsx { } } catch { - Write-Error ("Failed to convert {0} to XLSX." -f $xlsFile.FullName) + Write-Error ("Failed to convert {0} to XLSX. To avoid network issues or locking issues, you could try the -CacheToTemp parameter." -f $xlsFile.FullName) throw } finally { From 4e499abe878aebc2affd77e9775075b718fe8967 Mon Sep 17 00:00:00 2001 From: Edward Miller Date: Fri, 21 Jun 2024 01:19:06 -0500 Subject: [PATCH 7/7] allow setting just -CacheToDirectory for clarity --- Public/ConvertTo-ExcelXlsx.ps1 | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/Public/ConvertTo-ExcelXlsx.ps1 b/Public/ConvertTo-ExcelXlsx.ps1 index e911a536..7785dedb 100644 --- a/Public/ConvertTo-ExcelXlsx.ps1 +++ b/Public/ConvertTo-ExcelXlsx.ps1 @@ -9,10 +9,25 @@ function ConvertTo-ExcelXlsx { [parameter(Mandatory = $false)] [switch]$CacheToTemp, [parameter(Mandatory = $false)] - [string]$CacheDirectory + [string]$CacheToDirectory ) process { try { + + if ($CacheToTemp -and $CacheToDirectory) { + throw "Cannot specify both -CacheToTemp and -CacheToDirectory. Please choose one or the other." + } + + if ($CacheToTemp) { + $CacheToDirectory = [System.IO.Path]::GetTempPath() + } + + if ($CacheToDirectory) { + if (-not (Test-Path -Path $CacheToDirectory -PathType Container)) { + throw "CacheToDirectory path does not exist or is not writeable" + } + } + foreach ($singlePath in $Path) { if (-Not ($singlePath | Test-Path) ) { throw "File not found" @@ -54,11 +69,8 @@ function ConvertTo-ExcelXlsx { } } - if ($CacheToTemp) { - if (-not $CacheDirectory) { - $CacheDirectory = [System.IO.Path]::GetTempPath() - } - $tempPath = [System.IO.Path]::Combine($CacheDirectory, [System.IO.Path]::GetFileName($xlsFile.FullName)) + if ($CacheToDirectory) { + $tempPath = [System.IO.Path]::Combine($CacheToDirectory, [System.IO.Path]::GetFileName($xlsFile.FullName)) Write-Host ("Using Temp path: {0}" -f $tempPath) Copy-Item -Path $xlsFile.FullName -Destination $tempPath -Force $fileToProcess = $tempPath @@ -77,13 +89,13 @@ function ConvertTo-ExcelXlsx { } else { $workbook.SaveAs($xlsxPath, $xlFixedFormat) - if ($CacheToTemp) { + if ($CacheToDirectory) { Copy-Item -Path $xlsxPath -Destination $destinationXlsxPath -Force } } } catch { - Write-Error ("Failed to convert {0} to XLSX. To avoid network issues or locking issues, you could try the -CacheToTemp parameter." -f $xlsFile.FullName) + Write-Error ("Failed to convert {0} to XLSX. To avoid network issues or locking issues, you could try the -CacheToTemp or -CacheToDirectory parameter." -f $xlsFile.FullName) throw } finally { @@ -93,7 +105,7 @@ function ConvertTo-ExcelXlsx { $workbook = $null } - if ($CacheToTemp) { + if ($CacheToDirectory) { Remove-Item -Path $tempPath -Force Remove-Item -Path $xlsxPath -Force }