如何开放;萨瓦斯;然后从PowerShell4关闭Excel 2013(启用宏)工作簿

如何开放;萨瓦斯;然后从PowerShell4关闭Excel 2013(启用宏)工作簿,powershell,excel-interop,Powershell,Excel Interop,在上面的Com操作上进行搜索可以得到09年甚至更早的链接。也许它没有改变,但我发现自己遇到了错误,“它正被另一个进程使用。”——即使我的桌面上没有打开Excel应用程序。我必须重新启动才能继续 说清楚-我正在试图打开一个现有的文件;立即添加一张工作表,SaveAs()(非常有效);Close()-然后,重要的是,重复该循环。实际上,我在一个循环中创建了几十张新的工作表,该循环执行上述“打开主控”命令另存为();编辑材料;拯救接近 从我看到的示例来看,这不是PowerShell的典型工作流。粘贴在

在上面的Com操作上进行搜索可以得到09年甚至更早的链接。也许它没有改变,但我发现自己遇到了错误,“它正被另一个进程使用。”——即使我的桌面上没有打开Excel应用程序。我必须重新启动才能继续

说清楚-我正在试图打开一个现有的文件;立即添加一张工作表,
SaveAs()
(非常有效);Close()-然后,重要的是,重复该循环。实际上,我在一个循环中创建了几十张新的工作表,该循环执行上述“打开主控”命令<代码>另存为();编辑材料;拯救接近

从我看到的示例来看,这不是PowerShell的典型工作流。粘贴在最底部的是我的临时脚本-相当粗糙和不完整,但事情正在打开他们需要打开的东西,添加工作表也很有效-直到我知道我有正确的方法来干净地结束东西,我不担心迭代

我发现了几个解决关闭问题的示例:


根据我的经验,Quit方法不能很好地工作,尤其是在循环时。出现错误时,请打开任务管理器并查看“流程”选项卡,而不是重新启动。我敢打赌,您将看到Excel仍然处于打开状态——甚至可能有多个实例。我通过使用GetProcess查找Excel的所有实例并通过管道将其停止,从而解决了这个问题。这似乎不是必须的,但对我来说,它起到了关键作用。

作为我自己解决这个问题后的后续行动。我的解决方案围绕Ron Thompson的评论,减去函数调用:

# collect excel process ids before and after new excel background process is started
$priorExcelProcesses = Get-Process -name "*Excel*" | % { $_.Id }
$Excel = New-Object -ComObject Excel.Application
$postExcelProcesses = Get-Process -name "*Excel*" | % { $_.Id }

# your code here (probably looping through the Excel document in some way

# try to gently quit
$Excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)

# otherwise allow stop-process to clean up
$postExcelProcesses | ? { $priorExcelProcesses -eq $null -or $priorExcelProcesses -notcontains $_ } | % { Stop-Process -Id $_ }

您不应该跟踪进程并将其终止


我的经验是,要正确地完全关闭Excel(包括在循环中),还需要释放COM引用。在我自己的测试中,我发现删除Excel变量也可以确保不存在将保持Excel.exe打开的剩余引用(就像在ISE中调试一样)

在不执行上述操作的情况下,如果查看Task Manager,您可能会看到Excel仍在运行……在某些情况下,会有许多副本

这与COM对象如何包装在“运行时可调用包装器”中有关

以下是应使用的框架代码:

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$workbook = $excel.Workbooks.Add()
# or $workbook = $excel.Workbooks.Open($xlsxPath)

# do work with Excel...

$workbook.SaveAs($xlsxPath)
$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
# no $ needed on variable name in Remove-Variable call
Remove-Variable excel
试试这个

$filePath = "E:\TSMBackup\TSMDATAPull\ODCLXTSM01_VM.xlsx"

$excelObj = New-Object -ComObject Excel.Application

$excelObj.Visible = $true

$workBook = $excelObj.Workbooks.Open($filePath)

$workSheet = $workBook.Sheets.Item("Sheet1")

$workSheet.Select()

$workBook.RefreshAll()

$workBook.Save()

$excelObj.Quit()

我已经准备好告诉您,我已经检查了正在运行的进程,但是通过命令行运行显示的Excel进程没有通过任务管理器显示。谢谢!在其他用户打开Excel的服务器上使用
Stop Process-Name Excel
将导致PowerShell终止这些Excel实例。相反,在([System.Runtime.Interopservices.Marshall]::ReleaseComObject($Excel)){'cleanup Excel'}为了更好地衡量
[gc]::collect()| Out Null;[gc]::WaitForPendingFinalizers()| Out Null
我解决这个问题的方法是使用
函数startExcel(){$BeforeCel=@()$afterExcel=@();获取进程名“*Excel*”{$BEFOREXCEL+=$$.Id};$Excel=新对象-ComObject Excel.Application;获取进程名“*Excel*””{$afterExcel+=$.Id}
函数名Excel(){foreach($afterExcel中的Id){if($BEFOREXCEL-不包含$Id){Stop Process-Id$Id}}
只要上面注释的代码在收集PID的几毫秒内没有启动Excel实例,那么杀死其余的PID通常是安全的。我还没有失败过。/knocksonwood.Sledge-hammer-approach:
taskkill/F/IM-Excel.EXE
但是,我是Ron Thompson方法的粉丝。这非常清楚ner并不会终止在运行脚本之前打开的excel进程。在answers中编写代码时,使用“代码格式”选项会很有帮助。
# collect excel process ids before and after new excel background process is started
$priorExcelProcesses = Get-Process -name "*Excel*" | % { $_.Id }
$Excel = New-Object -ComObject Excel.Application
$postExcelProcesses = Get-Process -name "*Excel*" | % { $_.Id }

# your code here (probably looping through the Excel document in some way

# try to gently quit
$Excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)

# otherwise allow stop-process to clean up
$postExcelProcesses | ? { $priorExcelProcesses -eq $null -or $priorExcelProcesses -notcontains $_ } | % { Stop-Process -Id $_ }
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$workbook = $excel.Workbooks.Add()
# or $workbook = $excel.Workbooks.Open($xlsxPath)

# do work with Excel...

$workbook.SaveAs($xlsxPath)
$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
# no $ needed on variable name in Remove-Variable call
Remove-Variable excel
$filePath = "E:\TSMBackup\TSMDATAPull\ODCLXTSM01_VM.xlsx"

$excelObj = New-Object -ComObject Excel.Application

$excelObj.Visible = $true

$workBook = $excelObj.Workbooks.Open($filePath)

$workSheet = $workBook.Sheets.Item("Sheet1")

$workSheet.Select()

$workBook.RefreshAll()

$workBook.Save()

$excelObj.Quit()