I have an io.filesystemwatcher set up in powershell to monitor and automatically process data. It passes every test so far, but randomly it yields the following:
>> TerminatingError(New-Object): "Retrieving the COM class factory for component with CLSID {91493441-5A91-11CF-8700-00AA0060263B} failed due to the following error: 80080005 Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)).
I don't have a ton of microsoft office applications open when this happens. It seems encasing the code in a try-catch loop to essentially make it try again if this happens is a viable workaround some of the time, but just today it yielded this error 3 times in a row. What can I do to resolve this? I have thought of scheduling weekly restarts, but this seems like just a workaround whereas a solution may be available.
Can anyone further explain this error and how to overcome it?
Edit: Here are some of the scripts involved:
Function Report1{
param($Path)
[void][reflection.assembly]::loadwithpartialname("system.drawing")
$global:path = $path
$imgs = Get-ChildItem -Path $Path -Recurse -exclude *.pdf,*.datx | Where-Object { $_.Name -match '1.1_10x' -or $_.Name -match '1.2_10x' -or $_.Name -match '1.3_10x' -or $_.Name -match '1.4_10x' -or $_.Name -match '2.1_10x' -or $_.Name -match '2.2_10x' -or $_.Name -match '2.3_10x' -or $_.Name -match '2.4_10x' -or$_.Name -match '3.1_10x' -or $_.Name -match '3.2_10x' -or $_.Name -match '3.3_10x' -or $_.Name -match '3.4_10x' -or $_.Name -match '4.1_10x' -or $_.Name -match '4.2_10x' -or $_.Name -match '4.3_10x' -or $_.Name -match '4.4_10x' }
$files = @()
for ($i = 0; $i -lt $imgs.count; $i++){
#write-output $imgs[$i].FullName
$Files += $imgs[$i].FullName
}
$Rect = New-Object System.Drawing.Rectangle 289,198,137,29
$S1 = Export-ImageText $files[0] -Rect $Rect
$S2 = Export-ImageText $files[1] -Rect $Rect
$S3 = Export-ImageText $files[2] -Rect $Rect
$S4 = Export-ImageText $files[3] -Rect $Rect
$S5 = Export-ImageText $files[4] -Rect $Rect
$S6 = Export-ImageText $files[5] -Rect $Rect
$S7 = Export-ImageText $files[6] -Rect $Rect
$S8 = Export-ImageText $files[7] -Rect $Rect
$S9 = Export-ImageText $files[8] -Rect $Rect
$S10 = Export-ImageText $files[9] -Rect $Rect
$S11 = Export-ImageText $files[10] -Rect $Rect
$S12 = Export-ImageText $files[11] -Rect $Rect
$S13 = Export-ImageText $files[12] -Rect $Rect
$S14 = Export-ImageText $files[13] -Rect $Rect
$S15 = Export-ImageText $files[14] -Rect $Rect
$S16 = Export-ImageText $files[15] -Rect $Rect
$S1 = $s1 -replace "[^0-9.]"
$S2 = $s2 -replace "[^0-9.]"
$S3 = $s3 -replace "[^0-9.]"
$S4 = $s4 -replace "[^0-9.]"
$S5 = $s5 -replace "[^0-9.]"
$S6 = $s6 -replace "[^0-9.]"
$S7 = $s7 -replace "[^0-9.]"
$S8 = $s8 -replace "[^0-9.]"
$S9 = $s9 -replace "[^0-9.]"
$S10 = $s10 -replace "[^0-9.]"
$S11 = $s11 -replace "[^0-9.]"
$S12 = $s12 -replace "[^0-9.]"
$S13 = $s13 -replace "[^0-9.]"
$S14 = $s14 -replace "[^0-9.]"
$S15 = $s15 -replace "[^0-9.]"
$S16 = $s16 -replace "[^0-9.]"
$Template = "...\Report1_Template.xlsx"
$Base = $files[0] -split "\\" |Select-Object -Last 1
$Toolnum = $Base -split "_" |Select-Object -First 1
$Toolnum = $Toolnum.Replace("'", "")
$Savepath = split-path $path
$NewName = (-join($Savepath, "\\", $Toolnum, " Report1.xlsx"))
Copy-Item $Template -Destination $NewName
$Excel = New-Object -ComObject Excel.Application
$ExcelWorkBook = $Excel.Workbooks.Open($NewName)
$ExcelWorkSheet = $Excel.WorkSheets.item(1)
$ExcelWorkSheet.activate()
$Excel.visible = $true
$ExcelWorkSheet.Cells.Item(4,4) = $s1
$ExcelWorkSheet.Cells.Item(5,4) = $s2
$ExcelWorkSheet.Cells.Item(6,4) = $s3
$ExcelWorkSheet.Cells.Item(7,4) = $s4
$ExcelWorkSheet.Cells.Item(8,4) = $s5
$ExcelWorkSheet.Cells.Item(9,4) = $s6
$ExcelWorkSheet.Cells.Item(10,4) = $s7
$ExcelWorkSheet.Cells.Item(11,4) = $s8
$ExcelWorkSheet.Cells.Item(12,4) = $s9
$ExcelWorkSheet.Cells.Item(13,4) = $s10
$ExcelWorkSheet.Cells.Item(14,4) = $s11
$ExcelWorkSheet.Cells.Item(15,4) = $s12
$ExcelWorkSheet.Cells.Item(16,4) = $s13
$ExcelWorkSheet.Cells.Item(17,4) = $s14
$ExcelWorkSheet.Cells.Item(18,4) = $s15
$ExcelWorkSheet.Cells.Item(19,4) = $s16
$ExcelWorkBook.Save()
$ExcelWorkBook.Close()
$Excel.Quit()
}
Along with:
function Excel2PPT{
param ($xslx, $targetsheet, $targetrange, $pptx, $targetslide, $npath, $posL, $posT, $posW, $posH)
$Excel = New-Object -ComObject Excel.Application
$workbook = $Excel.workbooks.open($xslx)
$Excel.Visible= $true
$worksheet = $workbook.worksheets.Item($targetsheet)
$range = $worksheet.Range($targetrange)
$range.copy()
$objPPT = New-Object -ComObject Powerpoint.Application
$objPPT.Visible ='Msotrue'
$pp1 = $objPPT.Presentations.open($pptx)
#Add a slide to the presentation.
#$project = $objPPT.Presentations.Add()
$slide = $pp1.Slides.Item($targetslide)
#Paste the table into the slide.
$slide.Select()
#Start-Sleep -Seconds 5
$objPPT.CommandBars.ExecuteMso("PasteSourceFormatting")
Start-Sleep -Seconds 5
for ($j=1; $j -le $slide.Shapes.Count; $j++){
if ($slide.Shapes[$j].hastable -eq $True) {
$shape = $slide.Shapes[$j]
$shape.Left = $posL
$shape.Top = $posT
$shape.Width = $posW
$shape.Height = $posH
}
}
$pp1.Saveas($npath)
$Excel.close
$pp1.Close()
$Excel.Quit()
$objPPT.quit()
Stop-Process -name POWERPNT -Force
Stop-Process -name excel -Force
}
and:
function PicInsertPPT{
param($pic, $ppt, $targetslide, $savepath, $pos1, $pos2, $pos3, $pos4)
$objPPT = New-Object -ComObject Powerpoint.Application
$objPPT.Visible ='Msotrue'
$pp1 = $objPPT.Presentations.open($ppt)
$slide = $pp1.Slides.Item($targetslide)
$shape = $Slide.Shapes.AddPicture($pic, $pos1, $pos2, $pos3, $pos4)
$shape.Left = [int] $pos1
$shape.Top = [int] $pos2
$shape.Width = [int] $pos3
$shape.Height = [int] $pos4
$pp1.Saveas($savepath)
$pp1.Close()
$objPPT.quit()
Stop-Process -name POWERPNT -Force
}
and lastly:
Function TextReplace{
param ($p1, $f0a, $f1a, $savepath)
$ppo = New-Object -ComObject powerpoint.application
$presentation = $ppo.Presentations.open($p1)
for ($i = 1; $i -lt $presentation.Slides.Count+1; $i++){
for ($j = 1; $j -lt $presentation.Slides[$i].Shapes.Count+1; $j++){
if ($presentation.Slides[$i].Shapes[$j].TextFrame.TextRange){
$presentation.Slides[$i].Shapes[$j].TextFrame.TextRange.Replace($f0a, $f1a)
}
}
}
$presentation.saveas($savepath)
$presentation.close()
$ppo.quit()
Stop-Process -name POWERPNT -Force
}
I can include more if needed but the filesystem watcher basically calls functions that use these as needed to generate reports.
As I suspected, you are creating a lot of COM objects, but never release them from memory when you are done with them. Eventually, this will create errors from running out of memory resources.
I didn't have time to look into what the functions actually do however, but for the 'cleaning-up' code, I suggest you add all of the below to the end of the functions.
Function Report1:
End the code by quitting Excel end releasing the uses COM objects from memory.
$Excel.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkSheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkBook)
$null = System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Function Excel2PPT:
$Excel.Quit()
$objPPT.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkSheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkBook)
$null = System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)
$null = System.Runtime.Interopservices.Marshal]::ReleaseComObject($pp1)
$null = System.Runtime.Interopservices.Marshal]::ReleaseComObject($objPPT)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Function PicInsertPPT:
$objPPT.Quit()
$null = System.Runtime.Interopservices.Marshal]::ReleaseComObject($pp1)
$null = System.Runtime.Interopservices.Marshal]::ReleaseComObject($objPPT)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Function TextReplace:
$ppo.Quit()
$null = System.Runtime.Interopservices.Marshal]::ReleaseComObject($presentation)
$null = System.Runtime.Interopservices.Marshal]::ReleaseComObject($ppo)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
You could have more instances in the remainder of your script where COM objects are used. Always make sure to not let them linger in memory when no longer needed to avoid errors because of memory leaks.
User contributions licensed under CC BY-SA 3.0