如何在PowerShell脚本之后阻止Excel进程在后台运行?

时间:2016-08-19 17:46:47

标签: excel powershell windows-10 excel-2013

无论我尝试什么,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

6 个答案:

答案 0 :(得分:7)

我遇到了同样的问题并尝试了各种解决方案而没有成功。当我开始发布我保存为变量的所有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进程将保持打开状态。在我的代码中,我首先发布范围,表格等所有内容,然后我执行工作表,工作簿,最后是Excel应用程序本身。然后因为它似乎只有90%的时间都有效,我在最后添加了垃圾收集命令,最后得到的解决方案似乎每次都有效,而不必杀死进程。

注意:我的系统是带有PowerShell v5和Office 2013的Windows 8.1。

答案 1 :(得分:2)

下面是一个简单的例子。对于更复杂的程序,可能需要一些额外的代码。

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()

答案 2 :(得分:0)

上述解决方案对我不起作用,按我需要的顺序,最后一步是.saveas(file.xlsx),这意味着剩余的未保存文档仍然弹出gui界面,需要用户交互才能保存/不保存/取消。 。

我最后得到了以下内容,这些内容虽然很粗糙,但是对我有用。

脚本开头:

$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文档恢复对话框。

答案 3 :(得分:0)

替代答案:

我知道我的回复很晚,但是,请考虑采用以下方法来完成此操作。

  1. 首先,使用以下命令获取excel.exe的任何/所有实例的PID:

    tasklist /FI "imagename eq excel.exe"
    
  2. 运行脚本的一部分,以生成其excel.exe实例。使用步骤1中的命令来标识并保存excel.exe(例如wxyz)的新生成实例的PID,这与步骤1中保存的现有PID有所不同。

  3. 在脚本末尾,使用以下命令关闭特定实例(在步骤2中保存了PID):

    TASKKILL /f /PID wxyz
    

其中wxyz是第2步中保存的4位PID。

答案 4 :(得分:0)

  1. 创建Excel应用程序。
  2. 使其可见
  3. 获取应用程序的进程ID。
  4. 隐藏Excel应用程序。
  5. 停止进程我的进程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
    

答案 5 :(得分:0)

如果没有其他方法可以可靠地起作用,请尝试在退出前将Excel应用程序的DisplayAlerts设置为tru。

$xlapp.DisplayAlerts=$true
$xlapp.quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject([System.__ComObject]$xlapp)
$xlapp=$null
remove-variable xlapp
[GC]::Collect()

这总是对我有用。