11# SpreadsheetWrangler.ps1
22# GUI application for spreadsheet operations and folder backups
33
4- # Check for Excel and ImportExcel module availability
5- $script :UseExcelCOM = $false
4+ # Check for ImportExcel module availability
65$script :UseImportExcel = $false
76
8- try {
9- # Try to create Excel COM object to check if Excel is installed
10- $excelCheck = New-Object - ComObject Excel.Application - ErrorAction Stop
11- $excelCheck.Quit ()
12- [System.Runtime.Interopservices.Marshal ]::ReleaseComObject($excelCheck ) | Out-Null
13- # Excel is installed, but we'll force using ImportExcel module instead
14- Write-Host " Excel installation detected, but using ImportExcel module for better performance." - ForegroundColor Green
15- $script :UseExcelCOM = $false # Force to false even when Excel is available
16- } catch {
17- Write-Host " Excel is not installed or not accessible. Will use ImportExcel module." - ForegroundColor Yellow
18- }
19-
207# Check if ImportExcel module is installed
218if (-not (Get-Module - ListAvailable - Name ImportExcel)) {
229 Write-Host " ImportExcel module not found. Attempting to install..." - ForegroundColor Yellow
@@ -228,17 +215,8 @@ function Combine-Spreadsheets {
228215 )
229216
230217 try {
231- # Initialize Excel or ImportExcel based on availability
232- $excel = $null
233-
234- if ($script :UseExcelCOM ) {
235- Write-Log " Initializing Excel COM objects..." " White"
236- $excel = New-Object - ComObject Excel.Application
237- $excel.Visible = $false
238- $excel.DisplayAlerts = $false
239- } else {
240- Write-Log " Using ImportExcel module (Excel-free mode)..." " White"
241- }
218+ # Using ImportExcel module for all operations
219+ Write-Log " Using ImportExcel module for all operations..." " White"
242220
243221 # Create a dictionary to store spreadsheets by number
244222 $spreadsheetGroups = @ {}
@@ -291,13 +269,6 @@ function Combine-Spreadsheets {
291269 # Check if we found any spreadsheets
292270 if ($spreadsheetGroups.Count -eq 0 ) {
293271 Write-Log " No spreadsheets with matching numbers found in the selected folders." " Yellow"
294-
295- # Clean up Excel COM objects if they were used
296- if ($script :UseExcelCOM -and $excel ) {
297- $excel.Quit ()
298- [System.Runtime.Interopservices.Marshal ]::ReleaseComObject($excel ) | Out-Null
299- }
300-
301272 return $false
302273 }
303274
@@ -328,101 +299,7 @@ function Combine-Spreadsheets {
328299 $isFirstFile = $true
329300 $lastColumn = 0
330301
331- if ($script :UseExcelCOM ) {
332- # region Excel COM Processing
333- # Create a new workbook for the combined data
334- $combinedWorkbook = $excel.Workbooks.Add ()
335- $combinedWorksheet = $combinedWorkbook.Worksheets.Item (1 )
336- $combinedWorksheet.Name = " Combined"
337-
338- # Process each file in the group
339- foreach ($file in $files ) {
340- Write-Log " Combining: $file " " White"
341-
342- # Open the source workbook
343- $sourceWorkbook = $excel.Workbooks.Open ($file )
344- $sourceWorksheet = $sourceWorkbook.Worksheets.Item (1 )
345-
346- # Get used range
347- $usedRange = $sourceWorksheet.UsedRange
348- $lastRow = $usedRange.Rows.Count
349- $lastColumn = $usedRange.Columns.Count
350-
351- # Handle headers based on the ExcludeHeaders option
352- if ($ExcludeHeaders ) {
353- # No headers mode - always skip the first row (header) of all files
354- $startRow = 2 # Start from row 2 of each source file (skip header)
355-
356- # For the first file, set up the combined sheet to start at row 1 (no headers)
357- if ($isFirstFile ) {
358- $rowIndex = 1 # Start at row 1 in combined sheet (no headers)
359- $isFirstFile = $false
360- Write-Log " No Headers mode: Skipping header row from all files" " White"
361- }
362- } else {
363- # Include headers mode
364- if ($isFirstFile ) {
365- # Copy header row from first file only
366- $headerRange = $sourceWorksheet.Range ($sourceWorksheet.Cells (1 , 1 ), $sourceWorksheet.Cells (1 , $lastColumn ))
367- $headerRange.Copy () | Out-Null
368- $combinedWorksheet.Range ($combinedWorksheet.Cells (1 , 1 ), $combinedWorksheet.Cells (1 , $lastColumn )).PasteSpecial(-4163 ) | Out-Null
369- $rowIndex = 2 # Start data at row 2 (after header)
370- $isFirstFile = $false
371- }
372- # For all files in include headers mode, skip the header row except for the first file
373- $startRow = 2 # Skip header row from source files
374- }
375- if ($lastRow -ge $startRow ) {
376- $dataRange = $sourceWorksheet.Range ($sourceWorksheet.Cells ($startRow , 1 ), $sourceWorksheet.Cells ($lastRow , $lastColumn ))
377- $dataRange.Copy () | Out-Null
378- $combinedWorksheet.Range ($combinedWorksheet.Cells ($rowIndex , 1 ), $combinedWorksheet.Cells ($rowIndex + $lastRow - $startRow , $lastColumn )).PasteSpecial(-4163 ) | Out-Null
379- $rowIndex += $lastRow - $startRow + 1
380-
381- # Insert BLANK row between spreadsheets if option is enabled and this is not the last file
382- if ($InsertBlankRows -and ($file -ne $files [-1 ])) {
383- Write-Log " Inserting BLANK row after data from: $file " " White"
384-
385- # Determine which columns should have BLANK values
386- if (-not $ExcludeHeaders ) {
387- # If headers are included, add BLANK only to columns that have headers
388- for ($col = 1 ; $col -le $lastColumn ; $col ++ ) {
389- $headerText = $combinedWorksheet.Cells (1 , $col ).Text
390- if (-not [string ]::IsNullOrWhiteSpace($headerText )) {
391- $combinedWorksheet.Cells ($rowIndex , $col ).Value = " BLANK"
392- }
393- }
394- } else {
395- # If no headers, we need to determine which columns actually have data
396- # Look at the first few rows to determine which columns are used
397- $usedColumns = @ {}
398-
399- # Check the first 5 rows (or fewer if there aren't that many)
400- $rowsToCheck = [Math ]::Min(5 , $rowIndex - 1 )
401- for ($row = 1 ; $row -le $rowsToCheck ; $row ++ ) {
402- for ($col = 1 ; $col -le $lastColumn ; $col ++ ) {
403- $cellValue = $combinedWorksheet.Cells ($row , $col ).Text
404- if (-not [string ]::IsNullOrWhiteSpace($cellValue )) {
405- $usedColumns [$col ] = $true
406- }
407- }
408- }
409-
410- # Add BLANK only to columns that have data
411- foreach ($col in $usedColumns.Keys ) {
412- $combinedWorksheet.Cells ($rowIndex , $col ).Value = " BLANK"
413- }
414- }
415-
416- $rowIndex += 1
417- }
418- }
419-
420- # Close the source workbook without saving
421- $sourceWorkbook.Close ($false )
422- [System.Runtime.Interopservices.Marshal ]::ReleaseComObject($sourceWorkbook ) | Out-Null
423- }
424- # endregion Excel COM Processing
425- } else {
302+ # Process using ImportExcel
426303 # region ImportExcel Processing
427304 # Process each file in the group
428305 foreach ($file in $files ) {
@@ -514,140 +391,9 @@ function Combine-Spreadsheets {
514391 Write-Log " Error processing file $file `` : $errorMessage " " Red"
515392 }
516393 }
517- # endregion ImportExcel Processing
518- }
519394
520395 # Process special options and save the combined spreadsheet
521396 $combinedFilePath = Join-Path - Path $DestinationPath - ChildPath " Combined_Spreadsheet_$groupNumber .xlsx"
522-
523- if ($script :UseExcelCOM ) {
524- # region Excel COM Special Options Processing
525- if ($DuplicateQuantityTwoRows -or $NormalizeQuantities -or $ReverseDataRows ) {
526- # Find the 'Add to Quantity' column if it exists
527- $addToQuantityColIndex = $null
528-
529- # Re-open the workbook to process it
530- $tempWorkbook = $excel.Workbooks.Add ()
531- $tempWorksheet = $tempWorkbook.Worksheets.Item (1 )
532- $tempWorksheet.Name = " Combined"
533-
534- # Copy all data from combined worksheet to temp worksheet
535- $combinedWorksheet.UsedRange.Copy () | Out-Null
536- $tempWorksheet.Range (" A1" ).PasteSpecial(-4163 ) | Out-Null
537-
538- # Find the 'Add to Quantity' column if it exists
539- $lastColumn = $tempWorksheet.UsedRange.Columns.Count
540- $lastRow = $tempWorksheet.UsedRange.Rows.Count
541-
542- # Process Duplicate Qty=2 and Normalize Qty to 1 options
543- if ($DuplicateQuantityTwoRows -or $NormalizeQuantities ) {
544- for ($col = 1 ; $col -le $lastColumn ; $col ++ ) {
545- $headerText = $tempWorksheet.Cells (1 , $col ).Text
546- if ($headerText -eq " Add to Quantity" ) {
547- $addToQuantityColIndex = $col
548- Write-Log " Found 'Add to Quantity' column at index $col " " White"
549- break
550- }
551- }
552-
553- # Process the column if found
554- if ($addToQuantityColIndex ) {
555- # First duplicate rows with '2' in the 'Add to Quantity' column if option is enabled
556- if ($DuplicateQuantityTwoRows ) {
557- Write-Log " Processing 'Duplicate Qty=2' option..." " White"
558-
559- # We need to process from bottom to top to avoid index shifting issues
560- $rowsToInsert = @ ()
561-
562- for ($row = $lastRow ; $row -ge 2 ; $row -- ) {
563- $cellValue = $tempWorksheet.Cells ($row , $addToQuantityColIndex ).Text
564- if ($cellValue -eq " 2" ) {
565- Write-Log " Found row $row with quantity 2, duplicating..." " White"
566- $rowsToInsert += $row
567- }
568- }
569-
570- foreach ($row in $rowsToInsert ) {
571- # Insert a new row
572- $range = $tempWorksheet.Rows ($row )
573- $range.Copy () | Out-Null
574- $tempWorksheet.Rows ($row ).Insert(-4121 ) | Out-Null # -4121 is xlShiftDown
575- $lastRow ++
576- }
577-
578- Write-Log " Duplicated $ ( $rowsToInsert.Count ) rows with quantity 2" " Green"
579- }
580-
581- # Then normalize all quantities to '1' if option is enabled
582- if ($NormalizeQuantities ) {
583- Write-Log " Processing 'Normalize Qty to 1' option..." " White"
584- $changedCount = 0
585-
586- for ($row = 2 ; $row -le $lastRow ; $row ++ ) {
587- $cellValue = $tempWorksheet.Cells ($row , $addToQuantityColIndex ).Text
588- if ($cellValue -ne " 1" ) {
589- $tempWorksheet.Cells ($row , $addToQuantityColIndex ).Value = " 1"
590- $changedCount ++
591- }
592- }
593-
594- Write-Log " Normalized $changedCount cells to quantity 1" " Green"
595- }
596- } else {
597- Write-Log " 'Add to Quantity' column not found, skipping quantity processing" " Yellow"
598- }
599- }
600-
601- # Apply Reverse, Reverse option if enabled
602- if ($ReverseDataRows ) {
603- Write-Log " Applying 'Reverse, Reverse' option..." " White"
604-
605- # Determine the range to reverse (exclude header row if headers are included)
606- $startRow = if (-not $ExcludeHeaders ) { 2 } else { 1 }
607- $lastRow = $tempWorksheet.UsedRange.Rows.Count
608- $lastColumn = $tempWorksheet.UsedRange.Columns.Count
609-
610- if ($lastRow -ge $startRow ) {
611- # Create a temporary array to hold the reversed data
612- $dataArray = @ ()
613-
614- # Copy data to array (from bottom to top)
615- for ($row = $lastRow ; $row -ge $startRow ; $row -- ) {
616- $rowData = @ ()
617- for ($col = 1 ; $col -le $lastColumn ; $col ++ ) {
618- $rowData += $tempWorksheet.Cells ($row , $col ).Value
619- }
620- $dataArray += , $rowData
621- }
622-
623- # Write the reversed data back to the worksheet
624- for ($i = 0 ; $i -lt $dataArray.Count ; $i ++ ) {
625- $row = $startRow + $i
626- for ($col = 1 ; $col -le $lastColumn ; $col ++ ) {
627- if ($col -le $dataArray [$i ].Count) {
628- $tempWorksheet.Cells ($row , $col ).Value = $dataArray [$i ][$col - 1 ]
629- }
630- }
631- }
632-
633- Write-Log " Data rows reversed successfully" " Green"
634- } else {
635- Write-Log " Not enough data rows to reverse" " Yellow"
636- }
637- }
638-
639- # Save the processed workbook
640- $tempWorkbook.SaveAs ($combinedFilePath )
641- $tempWorkbook.Close ($true )
642- [System.Runtime.Interopservices.Marshal ]::ReleaseComObject($tempWorkbook ) | Out-Null
643- } else {
644- # Save the combined workbook normally
645- $combinedWorkbook.SaveAs ($combinedFilePath )
646- $combinedWorkbook.Close ($true )
647- [System.Runtime.Interopservices.Marshal ]::ReleaseComObject($combinedWorkbook ) | Out-Null
648- }
649- # endregion Excel COM Special Options Processing
650- } else {
651397 # region ImportExcel Special Options Processing
652398 # Process Duplicate Qty=2 and Normalize Qty to 1 options
653399 if ($DuplicateQuantityTwoRows -or $NormalizeQuantities ) {
@@ -751,8 +497,6 @@ function Combine-Spreadsheets {
751497 $errorMessage = $_.Exception.Message
752498 Write-Log " Error exporting combined data`` : $errorMessage " " Red"
753499 }
754- # endregion ImportExcel Special Options Processing
755- }
756500
757501 Write-Log " Saved combined spreadsheet: $combinedFilePath " " Green"
758502
@@ -761,13 +505,9 @@ function Combine-Spreadsheets {
761505 Update-ProgressBar $progressPercentage
762506 }
763507
764- # Clean up resources
765- if ($script :UseExcelCOM -and $excel ) {
766- $excel.Quit ()
767- [System.Runtime.Interopservices.Marshal ]::ReleaseComObject($excel ) | Out-Null
768- [System.GC ]::Collect()
769- [System.GC ]::WaitForPendingFinalizers()
770- }
508+ # No Excel COM resources to clean up
509+ [System.GC ]::Collect()
510+ [System.GC ]::WaitForPendingFinalizers()
771511
772512 Write-Log " Spreadsheet combining process completed." " Cyan"
773513 Update-ProgressBar 100
@@ -777,13 +517,7 @@ function Combine-Spreadsheets {
777517 catch {
778518 Write-Log " Error during spreadsheet combining: $_ " " Red"
779519
780- # Try to clean up Excel if an error occurs
781- if ($excel ) {
782- try {
783- $excel.Quit ()
784- [System.Runtime.Interopservices.Marshal ]::ReleaseComObject($excel ) | Out-Null
785- } catch {}
786- }
520+ # No Excel COM resources to clean up
787521
788522 [System.GC ]::Collect()
789523 [System.GC ]::WaitForPendingFinalizers()
0 commit comments