如何在执行 PowerShell 脚本后在后台停止来自 运行 的 Excel 进程?
How can I stop Excel processes from running in the background after a PowerShell script?
无论我尝试什么,Excel 2013 都会在 Windows 10 的后台继续 运行,无论我在 PowerShell 脚本末尾抛出什么命令。我已经尝试将我发现的所有建议添加到我的脚本的末尾,并且我打开的唯一 Excel 对象继续保持打开状态。这是我脚本末尾的内容。还有其他建议吗?
## Quit Excel and Terminate Excel Application process:
$xlsxwb.quit
$xlsxobj.Quit
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsxobj)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsxwb)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsxSh1)
Start-Sleep 1
'Excel processes: {0}' -f @(Get-Process excel -ea 0).Count
我运行遇到了同样的问题,尝试了各种解决方案都没有成功。当我开始释放保存为变量的所有 COM 对象时,我离得更近了,而不仅仅是工作簿、工作表和 Excel 应用程序的对象。
例如,拿下面的示例代码:
$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()
如果您只删除一个 ReleaseComObject 语句,Excel 进程将保持打开状态。在我的代码中,我首先发布了 运行ges、表格等所有内容,然后我发布了工作表、工作簿,最后发布了 Excel 应用程序本身。然后因为这似乎只有 90% 的时间有效,所以我在最后添加了垃圾收集命令,最终有了一个似乎每次都有效而无需终止进程的解决方案。
注意:我的系统是 Windows 8.1,带有 PowerShell v5 和 Office 2013。
下面是一个简单的例子。对于更复杂的过程,它可能需要一些额外的代码。
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()
以上解决方案对我不起作用,按照我需要的顺序,最后一步是 .saveas(file.xlsx)
,这意味着剩余的未保存文档仍然会弹出一个需要用户交互的 gui 界面 save/don' tsave/cancel。
我最终得到了以下结果,虽然很粗糙,但对我有用。
脚本开头:
$existingExcel = @()
Get-Process Excel | % {$existingExcel += $_.ID }
function Stop-Excel
{
Get-process EXCEL | % {IF($_.ID -notmatch $existingExcel){Stop-Process -ID $_.ID}}
}
并在脚本末尾
Stop-Excel
这样做的好处是可以完全销毁任何挥之不去的 excel 进程,而不会终止 运行 拥有此脚本的用户可能正在使用的任何其他活动 excel 进程。
缺点是当您下次加载时 excel 您会看到崩溃的 excel 文档恢复对话框。
备选答案:
我知道我的回复晚了,不过,请考虑以下方法来完成此操作。
开始,获取excel.exe
的any/all个实例的PID,使用命令:
tasklist /FI "imagename eq excel.exe"
运行 生成其 excel.exe
实例的脚本部分。使用步骤 1 中的命令识别并保存新生成的 excel.exe
实例的 PID(例如 wxyz
),这将不同于步骤 1 中保存的现有 PID。
在脚本结束时,关闭特定实例(PID 在步骤 2 中保存),使用命令:
TASKKILL /f /PID wxyz
其中 wxyz
是步骤 2 中保存的 4 位 PID。
- 创建 Excel 应用程序。
- 使其可见
- 获取应用程序的进程 ID。
- 隐藏 Excel 应用程序。
停止处理我的进程 ID。
示例代码
# 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 id
Stop-Process -Id $excelProcessId
如果没有其他可靠的方法,请尝试让 Excel 应用程序 DisplayAlerts 在退出前尝试。
$xlapp.DisplayAlerts=$true
$xlapp.quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject([System.__ComObject]$xlapp)
$xlapp=$null
remove-variable xlapp
[GC]::Collect()
这对我来说总是有效的。
无论我尝试什么,Excel 2013 都会在 Windows 10 的后台继续 运行,无论我在 PowerShell 脚本末尾抛出什么命令。我已经尝试将我发现的所有建议添加到我的脚本的末尾,并且我打开的唯一 Excel 对象继续保持打开状态。这是我脚本末尾的内容。还有其他建议吗?
## Quit Excel and Terminate Excel Application process:
$xlsxwb.quit
$xlsxobj.Quit
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsxobj)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsxwb)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsxSh1)
Start-Sleep 1
'Excel processes: {0}' -f @(Get-Process excel -ea 0).Count
我运行遇到了同样的问题,尝试了各种解决方案都没有成功。当我开始释放保存为变量的所有 COM 对象时,我离得更近了,而不仅仅是工作簿、工作表和 Excel 应用程序的对象。
例如,拿下面的示例代码:
$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()
如果您只删除一个 ReleaseComObject 语句,Excel 进程将保持打开状态。在我的代码中,我首先发布了 运行ges、表格等所有内容,然后我发布了工作表、工作簿,最后发布了 Excel 应用程序本身。然后因为这似乎只有 90% 的时间有效,所以我在最后添加了垃圾收集命令,最终有了一个似乎每次都有效而无需终止进程的解决方案。
注意:我的系统是 Windows 8.1,带有 PowerShell v5 和 Office 2013。
下面是一个简单的例子。对于更复杂的过程,它可能需要一些额外的代码。
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()
以上解决方案对我不起作用,按照我需要的顺序,最后一步是 .saveas(file.xlsx)
,这意味着剩余的未保存文档仍然会弹出一个需要用户交互的 gui 界面 save/don' tsave/cancel。
我最终得到了以下结果,虽然很粗糙,但对我有用。
脚本开头:
$existingExcel = @()
Get-Process Excel | % {$existingExcel += $_.ID }
function Stop-Excel
{
Get-process EXCEL | % {IF($_.ID -notmatch $existingExcel){Stop-Process -ID $_.ID}}
}
并在脚本末尾
Stop-Excel
这样做的好处是可以完全销毁任何挥之不去的 excel 进程,而不会终止 运行 拥有此脚本的用户可能正在使用的任何其他活动 excel 进程。
缺点是当您下次加载时 excel 您会看到崩溃的 excel 文档恢复对话框。
备选答案:
我知道我的回复晚了,不过,请考虑以下方法来完成此操作。
开始,获取
excel.exe
的any/all个实例的PID,使用命令:tasklist /FI "imagename eq excel.exe"
运行 生成其
excel.exe
实例的脚本部分。使用步骤 1 中的命令识别并保存新生成的excel.exe
实例的 PID(例如wxyz
),这将不同于步骤 1 中保存的现有 PID。在脚本结束时,关闭特定实例(PID 在步骤 2 中保存),使用命令:
TASKKILL /f /PID wxyz
其中 wxyz
是步骤 2 中保存的 4 位 PID。
- 创建 Excel 应用程序。
- 使其可见
- 获取应用程序的进程 ID。
- 隐藏 Excel 应用程序。
停止处理我的进程 ID。 示例代码
# 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 id Stop-Process -Id $excelProcessId
如果没有其他可靠的方法,请尝试让 Excel 应用程序 DisplayAlerts 在退出前尝试。
$xlapp.DisplayAlerts=$true
$xlapp.quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject([System.__ComObject]$xlapp)
$xlapp=$null
remove-variable xlapp
[GC]::Collect()
这对我来说总是有效的。