How can I stop Excel processes from running in the background after a PowerShell script?
I ran into the same problem and tried various solutions without success. I got closer when I started releasing all of the COM objects I saved as variables, not just the ones for the workbook, worksheet, and Excel application.
For example, take the following example code:
$Excel = New-Object -ComObject Excel.Application$Excel.Visible = $False$Workbook = $Excel.Workbooks.Open("C:\Temp\test.xlsx")$Worksheet = $Workbook.Worksheets.Item(1)$UsedRange = $Worksheet.UsedRange$Range = $Worksheet.Range("A1:B10")$Workbook.Close()$Excel.Quit()[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($Range)[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($UsedRange)[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($Worksheet)[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($Workbook)[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)[GC]::Collect()
If you were to take out just one of the ReleaseComObject statements, the Excel process would remain open. In my code I release all the ones like ranges, tables, etc. first and then I do the worksheet, workbook, and finally the Excel application itself. Then because that only seemed to work like 90% of the time, I added the garbage collection command at the end and finally had a solution that seems to work every time without having to kill the process.
Note: My system is Windows 8.1 with PowerShell v5 and Office 2013.
Here's a simple example below. It will likely require some additional code for more complex procedures.
function _FullQuit { while ( $this.Workbooks.Count -gt 0 ) { $this.Workbooks.Item(1).Close() } $this.Quit() [System.Runtime.InteropServices.Marshal]::ReleaseComObject($this) [System.GC]::Collect() [System.GC]::WaitForPendingFinalizers()}function New-Excel {$object = New-Object -ComObject "Excel.Application"$object | Add-Member -MemberType ScriptMethod -Name FullQuit -Value {_FullQuit}$object}$xl = New-Excel$wb1 = $xl.Workbooks.Open("C:\Data1.csv")$wb2 = $xl.Workbooks.Open("C:\Data2.csv")$xl.FullQuit()
- Create Excel Application.
- Make it visible
- Get Process Id of the application.
- Hide Excel Application.
Stop process my process id.Sample Code
# Create Excel Application$excel = New-Object -comobject Excel.Application# Make it visiable$excel.Visible = $true# Get Windows handle of the application$excelWinHwnd = $excel.Hwnd# Get Process Id of the application$process = Get-Process Excel | Where-Object {$_.MainWindowHandle -eq $excelWinHwnd}$excelProcessId = $process.Id# Hide the application : Run In background $excel.Visible = $false# Kill/Stop the process by idStop-Process -Id $excelProcessId