0

I've seen the many threads on this issue but none that seems to solve my issue.

I create Excel.Applicaiton object, open a xls, select a sheet, save it as csv, then close excel.

However excel.exe stays open and can be seen in the task manager.

This script will run on a server with many instances of it, so killing excel.exe is not an option.

One thing of note, is after the script execution is done, if i run " [System.GC]::Collect()" again it closes the excel.exe

full function below:

Function Convert-XLStoCSV
{
    Param(
        [string] $ExcelInputFilepath,
        [string] $CsvlOutputFilepath,
        [int]$SheetIndexToSave
    )
    Begin
    {
        write-host "Function:", $MyInvocation.MyCommand, "Started"
    }
    Process
    {
        Try
        {
            if ($null -eq $SheetIndexToSave)
            {
                $SheetIndexToSave = 1 
            }
            write-host "Adding Excel Type"
            $excel = New-Object -comobject Excel.Application
            write-host "Added Excel Type succesfully"
            $excel.DisplayAlerts = $false
            $excel.Visible = $false
            write-host "Opening $ExcelInputFilepath with Excel"
            $OpenWorkbook = $Excel.Workbooks.Open("$ExcelInputFilepath")
            write-host "Workbook opened correctly"
            $OpenWorkbook.ConflictResolution = 2
            write-host "Selecting sheet at index  $SheetIndexToSave"
            $sheetToSave = $OpenWorkbook.Sheets | Where-Object { $_.Index -eq $SheetIndexToSave }
            write-host "Starting to save sheet"
            $sheetToSave.SaveAs($CsvlOutputFilepath, 6)
            write-host "File saved to $CsvlOutputFilepath"
            write-host "Closing  Excel"
            $OpenWorkbook.saved = $True
            $OpenWorkbook.Close($false)
            $excel.Quit()



            [System.Runtime.Interopservices.Marshal]::FinalReleaseComObject($sheetToSave)
            [System.Runtime.Interopservices.Marshal]::FinalReleaseComObject($OpenWorkbook)
            [System.Runtime.Interopservices.Marshal]::FinalReleaseComObject($excel)
            Remove-Variable -Name sheetToSave
            Remove-Variable -Name OpenWorkbook 
            Remove-Variable -Name excel
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()
            [System.GC]::Collect(10, 1)
            [System.GC]::WaitForPendingFinalizers()
            write-host "Excel Closed"
        }
        Catch 
        {
            write-host "Function:", $MyInvocation.MyCommand, "Failed with exception:" "Error"
            write-host "Exception: $_" "Error"
            write-host "Exception: $($_.Exception.Message)" "Error"
            write-host "Inner Exception: $($_.Exception.InnerExceptionMessage)" "Error"
            write-host "StackTrace : $($_.Exception.StackTrace)" "Error"
            throw "Exception: $_"
        }
        finally
        {
            [System.GC]::Collect(10, 1)
        }
    }
    End
    {
        write-host "Function:", $MyInvocation.MyCommand, "Ended "
    }
}
MS_Convert-XLStoCSV -ExcelInputFilepath "D:\temp\recap.xls" -CsvlOutputFilepath "D:\temp\recap.csv" -SheetIndexToSave 1
# $ExcelInputFilepath = "D:\temp\recap.xls"
# $csvlOutputFilepath = "D:\temp\recap.csv"
# # $SheetIndexToSave = 1
Tom Kelly
  • 509
  • 2
  • 4
  • 16
  • Let us know if the answer to the linked question doesn't solve your problem. – mklement0 Nov 15 '19 at 21:45
  • Fwiw, I think the gotcha in this example is the use of ```where-object``` to iterate over the ```Sheets``` collection. I seem to remember from doing stuff with Excel and COM years ago that iterating over a collection would create "orphaned" references to objects. I used to end up doing something equivalent to ```for( $i=1; $i -le $coll.Count; $i++ ) { $item = $coll.Item($i); ...; $item = $null }``` to avoid dangling excel.exe processes. – mclayton Nov 15 '19 at 22:02

0 Answers0