Dispose of COM Objects in Powershell Script

1.3k views Asked by At

I have a scheduled task that runs a Powershell script. This Powershell script sends a HTTP request and searches through the returned HTML. As a result of this script, I am left with a bunch of dllhost processes that don't close. If I understand right, this is a result of COM objects.

The only variable related to COM objects is this:

$specifiedDiv = $request.ParsedHtml.Body.getElementsByTagName('div') |
    Where-Object{$_.getAttributeNode('class').Value -eq 'results'}

When I run $specifiedDiv.GetType(), I get this as the result:

IsPublic IsSerial Name                                     BaseType                                                                                                                                                              
-------- -------- ----                                     --------                                                                                                                                                              
True     False    __ComObject                              System.MarshalByRefObject 

My question is how can I close this object or prevent the script from creating the dllhost processes?

Edit:

    Function garbageCollect ([object]$ref){

            ([System.Runtime.Interopservices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0)
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()
        }
$parsedHtml = $request.ParsedHtml
$body = $parsedHtml.Body
$divs = $body.getElementsByTagName('div')


$classAttribute = $divs | Where-Object{$_.getAttributeNode('class').Value -eq 'results-found'}

        Remove-Variable -Name classAttribute
        Remove-Variable -Name parsedHtml
        Remove-Variable -Name body
        Remove-Variable -Name divs

        garbageCollect($parsedHtml)
        garbageCollect($body)

        foreach($div in $divs)
        {
            garbageCollect($div)
        }
        foreach($thing in $classAttribute)
        {
            garbageCollect($div)
        }

I tried the above but I still get the dllhost process.

1

There are 1 answers

6
Joseph Willcoxson On

Well, it's more complicated than that. There is

[System.Runtime.InteropServices.Marshal]::ReleaseComobject($specifiedDiv)

That might work... however, the way .NET works with COM objects, you might have a bunch of intermediate COM objects getting created all over the place. Such as $request, $request.ParsedHtml, $request.ParsedHtml.Body. Then there might be a whole bunch of other COM objects created in calls to $_.getAttributeNode('class').

$parsedHtml = $request.ParsedHtml
$body = $parsedHtml.Body
$divs = $body.getElementsByTagName('div')

foreach ($div in $divs)
{
   $attrNode = $div.getAttributeNode('class')
   
   if ($attrNode.Value -eq 'results')
   {
      $specificDiv = $attrNode
      break
   }
   else
   {
      [System.Runtime.Interopservices.Marshal]::ReleaseComObject($div)
   }
}

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($divs)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($body)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($parsedHtml)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($request)
### what is this ??? [System.Runtime.Interopservices.Marshal]::ReleaseComObject($requestHome)


#### Do something with $specificDiv if you want...however, you might create more COM objects...


[System.Runtime.Interopservices.Marshal]::ReleaseComObject($specifiedDiv)