如何打开;另存为;然后从PowerShell4关闭Excel 2013(启用宏)工作簿

时间:2013-11-11 14:05:14

标签: powershell excel-interop

对上述Com操作进行搜索会产生可追溯到'09甚至更早的链接。也许它没有改变,但我发现自己遇到了“被另一个进程使用的错误”。 - 即使我的桌面上没有打开Excel应用程序。我必须重新启动才能恢复。

要清楚 - 我正在尝试打开现有文件;立即SaveAs()(那么多),添加一张表Save(); Close() - 然后,重要的是,重复这个循环。实际上,我在循环中创建了几十个新表,执行上面的'Open Master; SaveAs();编辑东西;保存;关闭;

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

我找到了几个解决问题的例子:

From http://theolddogscriptingblog.wordpress.com/2012/06/07/get-rid-of-the-excel-com-object-once-and-for-all/

$x = New-Object -com Excel.Application
$x.Visible = $True
Start-Sleep 5
$x.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($x)
Remove-Variable x

And from http://social.technet.microsoft.com/Forums/windowsserver/en-US/24e57b61-e792-40c1-8aff-b0a8205f48ab/updated-opened-excel-using-powershell?forum=winserverpowershell

Set-ItemProperty $path -name IsReadOnly -value $false
$Excel.ActiveWorkBook.Save()
$openfile.Close() 
$openfile = $null 
$Excel.Quit() 
$Excel = $null 
[GC]::Collect() 

<>

function MakeNewBook($theWeek, $AffID){
    $ExcelFile = "C:\csv\InvoiceTemplate.xlsm"
    $Excel = New-Object -Com Excel.Application
    $Excel.Visible = $True  
    $Workbook = $Excel.Workbooks.Open($ExcelFile)
    $theWeek = $theWeek  -replace "C:\\csv\\", ""
    $theWeek = $theWeek  -replace "\.csv", ""

    $theWeek = "c:\csv\Invoices\" +$AffID +"_" + $theWeek + ".xlsm"

    $SummaryWorksheet = $Workbook.worksheets.Item(1)

    $Workbook.SaveAs($theWeek)
    return $Excel
}

function MakeNewSheet($myBook, $ClassID){
    $SheetName = "w"+$ClassID
    #$Excel = New-Object -Com Excel.Application
    #$Excel.Visible = $True  
    $wSheet = $myBook.WorkSheets.Add()

}

function SaveSheet ($myExcel)
{
    #$WorkBook.EntireColumn.AutoFit()
    #Set-ItemProperty $path -name IsReadOnly -value $false
    $myExcel.ActiveWorkBook.Save()

    $openfile= $myExcel.ActiveWorkBook
    $openfile.Close() 
    $openfile = $null 
    $myExcel.Quit() 
    $myExcel = $null 
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($myExcel)
    Remove-Variable $myExcel
    [GC]::Collect() 

}

$theWeek = "C:\csv\wkStart2013-11-04.csv"
$x = Import-Csv $theWeek

foreach ($xLine in $x){
    if ($x[0]){
        $AffID = $x[1].idAffiliate
        $myExcel = MakeNewBook $theWeek  $x[1].idAffiliate

        $ClassID = $x[1].idClass
        MakeNewSheet $myExcel $ClassID
        continue
    }
    SaveSheet($myExcel)
    $AffID = $_.$AffID
    $wID = $xLine.idClass
    #MakeNewSheet($wID)
    Echo "$wID"

}

4 个答案:

答案 0 :(得分:3)

作为跟进后我自己玩这个问题。我围绕Ron Thompson的评论减去了函数调用我的解决方案:

strace -f -o log

答案 1 :(得分:2)

我的经验是Quit方法不能很好地工作,特别是在循环时。当您收到错误而不是重新启动时,打开任务管理器并查看“进程”选项卡。我愿意打赌你会看到Excel仍然打开 - 甚至可能是它的多个实例。我通过使用Get-Process查找Excel的所有实例并将它们传递给Stop-Process解决了这个问题。似乎不应该这样做,但它为我做了诀窍。

答案 2 :(得分:1)

您不必跟踪进程并将其终止。

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

如果不执行上述操作,如果查看任务管理器,您可能会看到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

答案 3 :(得分:0)

试试这个

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